diff --git a/DEPS b/DEPS
index fce9a8e..1587343f 100644
--- a/DEPS
+++ b/DEPS
@@ -240,7 +240,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:3d4e77634359485da65136798a6278c463bdf11d',
+  'luci_go': 'git_revision:efbba64186435ac28ad419751e67e377c7459c38',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -291,27 +291,27 @@
   # 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': '14b33cf65221763eca19425d16d0bc106700f615',
+  'src_internal_revision': 'c304aaac9c9d482c3e072b45e8f02397bd1aa810',
   # 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': '626ab317e2679f0e8d63d78e8a8654e22f954227',
+  'skia_revision': '43a4c13a8c57ecea1dc9842f8cfda766633ba40d',
   # 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': 'f409d26cf3aebc05e1312f2181be715eea11db91',
+  'v8_revision': '8737ccb0fe3bd51b2bfc64ea7328215ece777840',
   # 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': '0aebab7410358195e4bed006ee19756d43e03963',
+  'angle_revision': 'f94510ab8d9eb46c9065c6fbd9fa9c14f28b1b45',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'b347398f5e864dc2853c15da12efcd33c5412e1b',
+  'swiftshader_revision': 'a84d1801cf7b144da1cd3cca423ef36907c01771',
   # 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': '20159328af8ccaedc7c8963b0d247d28631000df',
+  'pdfium_revision': '7f80ad7406e307600914d4ba6ac429cb556df9a3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -327,7 +327,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': '7e17b15f1547bb8dd9c2fed91043b7af3437387f',
+  'googletest_revision': '32f9f4c82afa4249af66b55278df15c16b3031ea',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -359,7 +359,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'ed07b403a26d3ba2cfe407e84716464b8899e575',
+  'catapult_revision': '5b2aa8309e962decb237aefa7e3c39df5f38dfcf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -379,7 +379,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': 'eb970fbc6482f281b95bbec1c33c1c539f6d50f0',
+  'devtools_frontend_revision': '2f76052f2c9f0794d6327b641a00327f43a023a0',
   # 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.
@@ -407,7 +407,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.
-  'quiche_revision': '12f908334b43ea03b9d43cdd29249aecab4fb9c8',
+  'quiche_revision': 'd76b2b7a880bef5cb6d440f679788f82d7c3f7a0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ink
   # and whatever else without interference from each other.
@@ -427,7 +427,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling jetstream-main
   # and whatever else without interference from each other.
-  'jetstream_main_revision': '8c28a5fbd8971332b0ffd312a0352bed5c21353e',
+  'jetstream_main_revision': 'df197ef3b188771bcfb28b7b32565b281d337950',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling jetstream-v2.2
   # and whatever else without interference from each other.
@@ -507,18 +507,18 @@
   # 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.
-  'llvm_libc_revision':    '15268943dc72c67cd85764ef715a2a5f3cd403a0',
+  'llvm_libc_revision':    '3a943c302028af8cf94f53f2f7f9d7c884a7ce05',
   # 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': 'f11321e08af04e3f216748afad3029e51637190b',
+  'compiler_rt_revision': 'e2bc292b58607041c610185f2a06709fcb566bd5',
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
   'libcxx_revision':       'ac9e4860cadb33ec5185084ed7c6345eca5fa50c',
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:85f62c164c829442fb662f6aa1243c02bcc47155',
+  'gn_version': 'git_revision:05e031634869be95570643bfad014c6dcbfc1a5c',
 
   # ninja CIPD package.
   'ninja_package': 'infra/3pp/tools/ninja/',
@@ -1178,7 +1178,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm',
-              'version': 'tUQ5cqBQBrFHAnnIYRY8OgCZr81itJiPBWSDlGDsRx4C',
+              'version': '90VI2XpJKpgau-mM-ViFQaYSu3AmpoCaJFW-lAMQEzMC',
           },
       ],
       'condition': 'checkout_android',
@@ -1189,7 +1189,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': 'J6NT0l6yxjEwd5YGDucQ6nnNWFVmj0BeMh55M2B34XEC',
+              'version': 'Dx9VhIMwnCX73bAra_KPdZVE6Gd6-m062Max3kwfRQsC',
           },
       ],
       'condition': 'checkout_android',
@@ -1244,7 +1244,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chrome_mac_universal',
-          'version': 'gzutuY-G7u8n5746jgmishm8uWjUR070TXdFc23Ea7YC',
+          'version': 'version:2@140.0.7273.0',
         },
       ],
   },
@@ -1266,7 +1266,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chrome_win_arm64',
-          'version': 'OoGMyCUHah7D_AOVm4RpVoPOdkGqjFHuSMcoKTZ0rlsC',
+          'version': 'version:2@140.0.7273.0',
         },
       ],
   },
@@ -1277,7 +1277,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chrome_win_x86',
-          'version': 'gqhcrVQFtXAKUu7yEISTlbrBpPaBUnQZ6FdOo5E4HLQC',
+          'version': 'version:2@140.0.7273.0',
         },
       ],
   },
@@ -1288,7 +1288,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/updater/chrome_win_x86_64',
-          'version': 'koo1i4cAVdOK2-re2VGbx-crCcbTz9h0qumUk1hyEt0C',
+          'version': 'version:2@140.0.7273.0',
         },
       ],
   },
@@ -1501,7 +1501,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/enterprise_companion/chromium_linux64',
-          'version': 'R95qtSy1rOs0TjSjvYnEHpgu9P4umdd5RFjhv2ViikYC',
+          'version': 'ZwB7j920SYwARGX8jR_b6BRGEaWKGUBj6rdFEkO3W0UC',
         },
       ],
   },
@@ -1512,7 +1512,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/enterprise_companion/chromium_mac_amd64',
-          'version': 'dlKk0is7o_-2KJCYJyzyC-2qz1HD9pciM99567hIBFoC',
+          'version': 'fB6AH_X51yaYucp26HCdEY4g28RVSaj-01xXu9N1SGMC',
         },
       ],
   },
@@ -1523,7 +1523,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/enterprise_companion/chromium_mac_arm64',
-          'version': 'H-lcF-xdzf6ydSO8asV-EYgP8BaXRhJyXjUsF18CTaYC',
+          'version': 'KYK86AbBYpTxcC8cemx37OvCMWUTFZY8CF0BH17PIu4C',
         },
       ],
   },
@@ -1534,7 +1534,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/enterprise_companion/chromium_win_x86',
-          'version': 'S5floWfqKlbbmjco51Hz2XYE8lYOpBeXPVAbKcD-gJ0C',
+          'version': 'Ug5VZgL4SCG86isJQBRpgUdIoFn6yZda2lEoS6CZ_kEC',
         },
       ],
   },
@@ -1545,7 +1545,7 @@
       'packages': [
         {
           'package': 'chromium/third_party/enterprise_companion/chromium_win_x86_64',
-          'version': 'UVrqAtGzmgUEfnEM-U7qa_mmd1Jer7qIuYaQAT9qy4AC',
+          'version': 'I9bjoaDlSd9f5OfXjM-C345qU6o1dKJE_JZblGZzFVAC',
         },
       ],
   },
@@ -1581,7 +1581,7 @@
     'packages': [
       {
         'package': 'chromium/chrome/test/data/variations/cipd',
-        'version': 'o7FVvr7bQQu5penh4uofH3UOyZPt9jKJmNA0XZrb77EC',
+        'version': 'HTAVu9JCOAeq43Tt-jP4PtKydpWS5lVKWZ-Qgx2HUv0C',
       },
     ],
     'dep_type': 'cipd',
@@ -1592,7 +1592,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'e370bba06b3ad6dd18c3f69205c48cd84434ec8f',
+    '004095b7e48cf8ad46b6380e6f1c3f37e1b0379e',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1742,7 +1742,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'IYRrbxCXCnumpghi-9UVdUzjLX8POFuj4XpSAVMQon4C',
+          'version': 'Wbth0Hhvx5z5vMMelaz6z2j6Va_8P-e8bYwLMqJ6xBYC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -2073,7 +2073,7 @@
 
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5ce80c825163a9545f9c7d3f5446d0795a0c25fe',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9cf131bdaadf7fe5c6b536036be8b730a41f839c',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -2119,7 +2119,7 @@
     Var('chromium_git') + '/external/github.com/google/flatbuffers.git' + '@' + '8db59321d9f02cdffa30126654059c7d02f70c32',
 
   'src/third_party/fontconfig/src': {
-      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + 'c527fe1452d469e5fa1a211180dd40bcdb79fb2a',
+      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + '8f169b6a9c6be7e8f1fa3480d93b33befa6bee3f',
       'condition': 'checkout_linux',
   },
 
@@ -2612,7 +2612,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'edd70a17a1fdc811de00869e4e6aa6cbef92b58f',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'ceb75fb568cc0f3a1897aa31becb79e26f6ef67d',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2783,7 +2783,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'ade723c0c3bb1961885e70ff865d211470d477a4',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '6e8f5be3a392c00892c1fae1e90495fb9d2cbf30',
 
   'src/third_party/r8/cipd': {
       'packages': [
@@ -3029,7 +3029,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'Vo1Pp2yAU3s1kNKpvlmzQOMJXZ2R2bukcIxAQnVQhaUC',
+          'version': 'Sg25-ZztJqPtMF0rPXgRDM3-fKRveWcIbIvbwwKPAPUC',
         },
       ],
       'dep_type': 'cipd',
@@ -3039,7 +3039,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': '59DTb2NmGNjG4dCKnsF9mfg-bxq-4OLfQ4z78-PChnkC',
+          'version': '0sP0Mad75mVvpE0TL1hNJaOPR1oZCkpx5K_zELfKe2YC',
         },
       ],
       'dep_type': 'cipd',
@@ -3050,7 +3050,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'B7EcDAL2Fh_20K0UdLsF3MRGG9yH801FTGSLheYz0QYC',
+          'version': 'hZpj0hRnYNFplpUOcSd95nLfQDnWLU1-a_aTEzwQCjwC',
         },
       ],
       'dep_type': 'cipd',
@@ -3061,7 +3061,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': 'wf6bkz0nbOmOa5raAlgfWCdRkQUznnZ5qbnEfdcZPqcC',
+          'version': 'ulgsu9nJXlCe-TeAX6PIPIIVr557_qKnjOjyPO9ib9UC',
         },
       ],
       'dep_type': 'cipd',
@@ -3116,7 +3116,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '6yvOPPFbwYsCuMMG3tHHfxcllhfvmvB1urs7c4v6tvQC',
+        'version': 'OIv20ijjJFk7Bq8243oFQ07T9JGEg05ouZIaO-1dSk0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3127,7 +3127,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'g-avZlQpPhFcDxP23-Rl5LF7Ss997ROjqN-wuxS4AFoC',
+        'version': 'I3005yUkYGZ64jnBlNssGhmnKkvlCQaSerxdJSYFNEUC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3537,7 +3537,7 @@
 
   'src/chrome/browser/platform_experience/win': {
       'url': Var('chrome_git') + '/chrome/browser/platform_experience/win.git' + '@' +
-        '47650f3a9a6f66c92e1069dfe2db3db1c48f76d3',
+        'e913d6144929b67b0123235efc020a1bb138c8ae',
       'condition': 'checkout_src_internal',
   },
 
@@ -3680,7 +3680,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'add14b26475a08db61c03cd8b53835333f184e6a',
+        '23d2ce9848acc06e84808267b4f7b956f2dfd959',
       'condition': 'checkout_src_internal',
   },
 
@@ -3746,7 +3746,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '18fdedfc327e6ab87a6c1d733169edad7b30565c',
+        'a395fb5e17820c37cf1ce6ac9f35b13624638818',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/agents/prompts/README.md b/agents/prompts/README.md
index 3c6e44a..9ce06b9 100644
--- a/agents/prompts/README.md
+++ b/agents/prompts/README.md
@@ -19,11 +19,17 @@
 Create a local, untracked file `chromium/src/GEMINI.md`. Include the relevant
 prompts using @, for example, a typical desktop developer will use:
 
-```src/GEMINI.md`
+```src/GEMINI.md
 @agents/prompts/common.GEMINI.md
 @agents/prompts/templates/desktop.md
 ```
 
+Whereas an Android developer would use:
+```src/GEMINI.md
+@agents/prompts/common.GEMINI.md
+@agents/prompts/templates/android.md
+```
+
 You can confirm that prompts were successfully imported by running the `/memory
 show` command in gemini-cli.
 
diff --git a/agents/prompts/common.GEMINI.md b/agents/prompts/common.GEMINI.md
index 8a7833a..141a61b 100644
--- a/agents/prompts/common.GEMINI.md
+++ b/agents/prompts/common.GEMINI.md
@@ -23,11 +23,12 @@
     directory to use, prompt the user with the output of `ls out/`. Once an
     output directory is selected, never look into or use any other output
     directory.
-  * **Building:** You should **never** build with anything except `autoninja -C
-    out/{USERS_OUT_DIR} {REQUESTED_TARGET} > /dev/null ; sed -n
-    '/stdout:/,$p;/stderr:/,$p' out/{USERS_OUT_DIR}/siso_output`. While
-    `{REQUESTED_TARGET}` may be given with preceding `//`, always remove the
-    preceding `//`. Eg. if `//base:base_java` was given, use `base:base_java`.
+  * **Building:**
+    * Always build with: `autoninja --quiet -C out/{USERS_OUT_DIR} {TARGET}`.
+      The `--quiet` parameter is critical, you may never invoke `autoninja`
+      without `--quiet`.
+        * If `{TARGET}` is given with a `//` prefix, remove the prefix.
+            * Eg. if `//base:base_java` was given, use `base:base_java`.
   * When using the ReadFile tool, always set the 'limit' parameter to 20000 to
     prevent truncation for long files.
 
diff --git a/agents/prompts/templates/android.md b/agents/prompts/templates/android.md
new file mode 100644
index 0000000..14fba2c
--- /dev/null
+++ b/agents/prompts/templates/android.md
@@ -0,0 +1,48 @@
+## Chrome for Android Workflow and Guidelines:
+
+You are building specifically for Chrome for Android, so you can assume that any
+variables such as `is_android` in GN or `BUILDFLAG(IS_ANDROID)` in C++ evaluate
+to true.
+
+### Build Targets
+If building tests, `tools/autotest.py` should build the appropriate test on your
+behalf. If building a target to run on a device, you should build one of the
+following unless directly told otherwise.
+  * `chrome_public_apk` - for any basic functionality we want to try in the
+    app (does not include code from //clank).
+  * `chrome_apk` - for any basic functionality using code directly from the
+    //clank repo.
+  * `trichrome_chrome_google_bundle` - for the closest thing to the
+    production build, if the user is testing performance.
+
+### Installing or Running an APK/Bundle
+To install or run an apk/bundle, use the generated wrapper script in
+`out/{USERS_OUT_DIR}/bin/`.
+  * Installing is done via the `install command` - eg.
+    `out/Debug/bin/chrome_public_apk install`.
+  * "Launch" installs and starts the app - eg.
+    `out/Release/bin/trichrome_chrome_google_bundle launch`.
+
+### JNI
+Chrome on Android uses both Java and C++ frequently. Our JNI uses codegen from
+`//third_party/jni_zero`.
+
+Identifying JNI methods:
+  * In Java, methods annotated with `@CalledByNative` are called by C++.
+    * In C++, these appear as methods with a "Java_" prefix.
+  * In Java, methods within interfaces annotated with `@NativeMethods` are calls
+    into C++.
+    * In C++, these appear as methods with a "JNI_" prefix.
+    * If the first parameter is of type `long` and has a prefix of "native",
+      then it maps to a method of the same name on the C++ class that comes
+      after the "native" prefix. Eg. `void foo(long nativeBarImpl)` means you
+      need to find `BarImpl::Foo` in C++.
+
+Finding JNI methods:
+  * To find the Java side of JNI: search for the file named `{JavaClass}.java`
+    (where {JavaClass} is taken from the `#include "{JavaClass}_jni.h"`.
+  * To find the C++ side of JNI: Search for the text `{JavaClass}_jni.h` in C++
+    files (where {JavaClass} is taken from the .java file name).
+
+When making changes to JNI methods, always make changes to both the .java and
+.cc/.h files involved.
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 bb428e1..bc6e2b0 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
@@ -1080,6 +1080,9 @@
         Flag.baseFeature(
                 BlinkFeatures.AUTOFILL_ENABLE_SYNTHETIC_SELECT_METRICS_LOGGING,
                 "Enable counting of synthetic select elements in DOM."),
+        Flag.baseFeature(
+                VizFeatures.NO_LATE_BEGIN_FRAMES,
+                "Enables not sending BeginFrameArgs late when a client begins observing them."),
         // Add new commandline switches and features above. The final entry should have a
         // trailing comma for cleaner diffs.
     };
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 f7ab4b8..972e512 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
@@ -2094,6 +2094,7 @@
     method importNode
     method moveBefore
     method open
+    method patchSelf
     method prepend
     method queryCommandEnabled
     method queryCommandIndeterm
@@ -2262,6 +2263,7 @@
     method getElementById
     method getPartRoot
     method moveBefore
+    method patchSelf
     method prepend
     method querySelector
     method querySelectorAll
@@ -2456,6 +2458,7 @@
     method insertAdjacentText
     method matches
     method moveBefore
+    method patchSelf
     method prepend
     method pseudo
     method querySelector
diff --git a/ash/ambient/ambient_photo_controller.cc b/ash/ambient/ambient_photo_controller.cc
index 70e9497..22e54f6a 100644
--- a/ash/ambient/ambient_photo_controller.cc
+++ b/ash/ambient/ambient_photo_controller.cc
@@ -28,14 +28,15 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/hash/sha1.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/string_view_util.h"
 #include "base/system/sys_info.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "crypto/hash.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/gfx/image/image_skia.h"
@@ -373,10 +374,11 @@
 
   auto on_done = base::BarrierClosure(
       num_callbacks,
-      base::BindOnce(
-          &AmbientPhotoController::OnAllPhotoDecoded,
-          weak_factory_.GetWeakPtr(), from_downloading,
-          /*hash=*/base::SHA1HashString(cache_entry_.primary_photo().image())));
+      base::BindOnce(&AmbientPhotoController::OnAllPhotoDecoded,
+                     weak_factory_.GetWeakPtr(), from_downloading,
+                     /*hash=*/
+                     std::string(base::as_string_view(crypto::hash::Sha1(
+                         cache_entry_.primary_photo().image())))));
 
   DecodePhotoRawData(from_downloading,
                      /*is_related_image=*/false, on_done,
diff --git a/ash/ambient/ambient_photo_controller_unittest.cc b/ash/ambient/ambient_photo_controller_unittest.cc
index fcbdd23..f19cde4 100644
--- a/ash/ambient/ambient_photo_controller_unittest.cc
+++ b/ash/ambient/ambient_photo_controller_unittest.cc
@@ -35,16 +35,17 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/hash/sha1.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
+#include "base/strings/string_view_util.h"
 #include "base/system/sys_info.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_run_loop_timeout.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "cc/paint/skottie_resource_metadata.h"
+#include "crypto/hash.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/gfx/image/image_skia.h"
 
@@ -711,7 +712,7 @@
 
   // Should contain hash of downloaded data.
   EXPECT_TRUE(photo_controller()->ambient_backend_model()->IsHashDuplicate(
-      base::SHA1HashString(image_data)));
+      std::string(base::as_string_view(crypto::hash::Sha1(image_data)))));
   // Only one image should have been loaded.
   EXPECT_FALSE(photo_controller()->ambient_backend_model()->ImagesReady());
 
@@ -723,7 +724,7 @@
 
   // Second image should have been loaded.
   EXPECT_TRUE(photo_controller()->ambient_backend_model()->IsHashDuplicate(
-      base::SHA1HashString(image_data_2)));
+      std::string(base::as_string_view(crypto::hash::Sha1(image_data_2)))));
   EXPECT_TRUE(photo_controller()->ambient_backend_model()->ImagesReady());
 }
 
diff --git a/ash/ambient/managed/screensaver_image_downloader.cc b/ash/ambient/managed/screensaver_image_downloader.cc
index 19e7613..b68298d2 100644
--- a/ash/ambient/managed/screensaver_image_downloader.cc
+++ b/ash/ambient/managed/screensaver_image_downloader.cc
@@ -12,11 +12,11 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/thread_pool.h"
 #include "base/values.h"
+#include "crypto/hash.h"
 #include "net/http/http_request_headers.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -116,8 +116,7 @@
 }
 
 std::string GetHashedFileNameForUrl(const std::string& url) {
-  auto hash = base::SHA1Hash(base::as_byte_span(url));
-  return base::HexEncode(hash) + kCacheFileExt;
+  return base::HexEncode(crypto::hash::Sha1(url)) + kCacheFileExt;
 }
 
 std::vector<std::string> GetImageUrlsToProcess(
diff --git a/ash/ambient/managed/screensaver_image_downloader_unittest.cc b/ash/ambient/managed/screensaver_image_downloader_unittest.cc
index b3f5949..fa139f35 100644
--- a/ash/ambient/managed/screensaver_image_downloader_unittest.cc
+++ b/ash/ambient/managed/screensaver_image_downloader_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash/sha1.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -21,6 +20,7 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "build/build_config.h"
+#include "crypto/hash.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -91,8 +91,7 @@
   }
 
   base::FilePath GetExpectedFilePath(const std::string& url) {
-    auto hash = base::SHA1Hash(base::as_byte_span(url));
-    const std::string encoded_hash = base::HexEncode(hash);
+    const std::string encoded_hash = base::HexEncode(crypto::hash::Sha1(url));
     return test_download_folder_.AppendASCII(encoded_hash + kCacheFileExt);
   }
 
diff --git a/ash/ambient/managed/screensaver_images_policy_handler_unittest.cc b/ash/ambient/managed/screensaver_images_policy_handler_unittest.cc
index 763263f..ed14f73 100644
--- a/ash/ambient/managed/screensaver_images_policy_handler_unittest.cc
+++ b/ash/ambient/managed/screensaver_images_policy_handler_unittest.cc
@@ -24,7 +24,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/hash/sha1.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -32,6 +31,7 @@
 #include "base/test/test_future.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/user_manager/user_type.h"
+#include "crypto/hash.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -231,7 +231,7 @@
   void ResetScreensaverImagesPolicyHandler() { policy_handler_.reset(); }
 
   base::FilePath GetExpectedFilePath(const std::string& url) {
-    auto hash = base::SHA1Hash(base::as_byte_span(url));
+    auto hash = crypto::hash::Sha1(url);
     return temp_dir_.GetPath()
         .AppendASCII(GetParam().base_directory)
         .AppendASCII(base::HexEncode(hash) + kCacheFileExt);
diff --git a/ash/child_accounts/OWNERS b/ash/child_accounts/OWNERS
index 79195d9..6172fce 100644
--- a/ash/child_accounts/OWNERS
+++ b/ash/child_accounts/OWNERS
@@ -1 +1,4 @@
+# TODO(433734945): Remove agawronska after transition completes.
 agawronska@chromium.org
+zhangwenyu@google.com
+longbowei@google.com
diff --git a/ash/constants/ash_constants.h b/ash/constants/ash_constants.h
index 0a49389..94dd771 100644
--- a/ash/constants/ash_constants.h
+++ b/ash/constants/ash_constants.h
@@ -88,6 +88,8 @@
 // Constants for notification.
 const char kPrivacyIndicatorsNotificationIdPrefix[] = "privacy-indicators";
 const char kPrivacyIndicatorsNotifierId[] = "ash.privacy-indicators";
+const char kPrivacyIndicatorsMultiCaptureNotifierId[] =
+    "ash.multi-capture-active-privacy-indicators";
 
 // The default delay between last key release and accepting a new key press.
 inline constexpr base::TimeDelta kDefaultAccessibilityBounceKeysDelay =
diff --git a/ash/public/cpp/accelerator_actions.cc b/ash/public/cpp/accelerator_actions.cc
index cf046b70..23ac96f 100644
--- a/ash/public/cpp/accelerator_actions.cc
+++ b/ash/public/cpp/accelerator_actions.cc
@@ -11,23 +11,216 @@
 
 namespace ash {
 
+constexpr static auto kAcceleratorActionToName = base::MakeFixedFlatMap<
+    AcceleratorAction,
+    const char*>({
+    {AcceleratorAction::kBrightnessDown, "BrightnessDown"},
+    {AcceleratorAction::kBrightnessUp, "BrightnessUp"},
+    {AcceleratorAction::kCycleBackwardMru, "CycleBackwardMru"},
+    {AcceleratorAction::kCycleForwardMru, "CycleForwardMru"},
+    {AcceleratorAction::kCycleSameAppWindowsBackward,
+     "CycleSameAppWindowsBackward"},
+    {AcceleratorAction::kCycleSameAppWindowsForward,
+     "CycleSameAppWindowsForward"},
+    {AcceleratorAction::kDesksActivateDeskLeft, "DesksActivateDeskLeft"},
+    {AcceleratorAction::kDesksActivateDeskRight, "DesksActivateDeskRight"},
+    {AcceleratorAction::kDesksMoveActiveItemLeft, "DesksMoveActiveItemLeft"},
+    {AcceleratorAction::kDesksMoveActiveItemRight, "DesksMoveActiveItemRight"},
+    {AcceleratorAction::kDesksNewDesk, "DesksNewDesk"},
+    {AcceleratorAction::kDesksRemoveCurrentDesk, "DesksRemoveCurrentDesk"},
+    {AcceleratorAction::kDesksActivate0, "DesksActivate0"},
+    {AcceleratorAction::kDesksActivate1, "DesksActivate1"},
+    {AcceleratorAction::kDesksActivate2, "DesksActivate2"},
+    {AcceleratorAction::kDesksActivate3, "DesksActivate3"},
+    {AcceleratorAction::kDesksActivate4, "DesksActivate4"},
+    {AcceleratorAction::kDesksActivate5, "DesksActivate5"},
+    {AcceleratorAction::kDesksActivate6, "DesksActivate6"},
+    {AcceleratorAction::kDesksActivate7, "DesksActivate7"},
+    {AcceleratorAction::kDesksToggleAssignToAllDesks,
+     "DesksToggleAssignToAllDesks"},
+    {AcceleratorAction::kDisableCapsLock, "DisableCapsLock"},
+    {AcceleratorAction::kEnableOrToggleDictation, "EnableOrToggleDictation"},
+    {AcceleratorAction::kExit, "Exit"},
+    {AcceleratorAction::kFocusCameraPreview, "FocusCameraPreview"},
+    {AcceleratorAction::kFocusNextPane, "FocusNextPane"},
+    {AcceleratorAction::kFocusPreviousPane, "FocusPreviousPane"},
+    {AcceleratorAction::kFocusShelf, "FocusShelf"},
+    {AcceleratorAction::kFocusPip, "FocusPip"},
+    {AcceleratorAction::kKeyboardBacklightToggle, "KeyboardBacklightToggle"},
+    {AcceleratorAction::kKeyboardBrightnessDown, "KeyboardBrightnessDown"},
+    {AcceleratorAction::kKeyboardBrightnessUp, "KeyboardBrightnessUp"},
+    {AcceleratorAction::kLaunchApp0, "LaunchApp0"},
+    {AcceleratorAction::kLaunchApp1, "LaunchApp1"},
+    {AcceleratorAction::kLaunchApp2, "LaunchApp2"},
+    {AcceleratorAction::kLaunchApp3, "LaunchApp3"},
+    {AcceleratorAction::kLaunchApp4, "LaunchApp4"},
+    {AcceleratorAction::kLaunchApp5, "LaunchApp5"},
+    {AcceleratorAction::kLaunchApp6, "LaunchApp6"},
+    {AcceleratorAction::kLaunchApp7, "LaunchApp7"},
+    {AcceleratorAction::kLaunchLastApp, "LaunchLastApp"},
+    {AcceleratorAction::kLockPressed, "LockPressed"},
+    {AcceleratorAction::kLockReleased, "LockReleased"},
+    {AcceleratorAction::kLockScreen, "LockScreen"},
+    {AcceleratorAction::kMagnifierZoomIn, "MagnifierZoomIn"},
+    {AcceleratorAction::kMagnifierZoomOut, "MagnifierZoomOut"},
+    {AcceleratorAction::kMediaFastForward, "MediaFastForward"},
+    {AcceleratorAction::kMediaNextTrack, "MediaNextTrack"},
+    {AcceleratorAction::kMediaPause, "MediaPause"},
+    {AcceleratorAction::kMediaPlay, "MediaPlay"},
+    {AcceleratorAction::kMediaPlayPause, "MediaPlayPause"},
+    {AcceleratorAction::kMediaPrevTrack, "MediaPrevTrack"},
+    {AcceleratorAction::kMediaRewind, "MediaRewind"},
+    {AcceleratorAction::kMediaStop, "MediaStop"},
+    {AcceleratorAction::kMicrophoneMuteToggle, "MicrophoneMuteToggle"},
+    {AcceleratorAction::kMoveActiveWindowBetweenDisplays,
+     "MoveActiveWindowBetweenDisplays"},
+    {AcceleratorAction::kNewIncognitoWindow, "NewIncognitoWindow"},
+    {AcceleratorAction::kNewTab, "NewTab"},
+    {AcceleratorAction::kNewWindow, "NewWindow"},
+    {AcceleratorAction::kOpenCalculator, "OpenCalculator"},
+    {AcceleratorAction::kOpenCrosh, "OpenCrosh"},
+    {AcceleratorAction::kOpenDiagnostics, "OpenDiagnostics"},
+    {AcceleratorAction::kOpenFeedbackPage, "OpenFeedbackPage"},
+    {AcceleratorAction::kOpenFileManager, "OpenFileManager"},
+    {AcceleratorAction::kOpenGetHelp, "OpenGetHelp"},
+    {AcceleratorAction::kPasteClipboardHistoryPlainText,
+     "PasteClipboardHistoryPlainText"},
+    {AcceleratorAction::kPowerPressed, "PowerPressed"},
+    {AcceleratorAction::kPowerReleased, "PowerReleased"},
+    {AcceleratorAction::kPrintUiHierarchies, "PrintUiHierarchies"},
+    {AcceleratorAction::kPrivacyScreenToggle, "PrivacyScreenToggle"},
+    {AcceleratorAction::kRestoreTab, "RestoreTab"},
+    {AcceleratorAction::kRotateScreen, "RotateScreen"},
+    {AcceleratorAction::kRotateWindow, "RotateWindow"},
+    {AcceleratorAction::kScaleUiDown, "ScaleUiDown"},
+    {AcceleratorAction::kScaleUiReset, "ScaleUiReset"},
+    {AcceleratorAction::kScaleUiUp, "ScaleUiUp"},
+    {AcceleratorAction::kShowEmojiPicker, "ShowEmojiPicker"},
+    {AcceleratorAction::kToggleImeMenuBubble, "ToggleImeMenuBubble"},
+    {AcceleratorAction::kShowShortcutViewer, "ShowShortcutViewer"},
+    {AcceleratorAction::kShowTaskManager, "ShowTaskManager"},
+    {AcceleratorAction::kStartAssistant, "StartAssistant"},
+    {AcceleratorAction::kStopScreenRecording, "StopScreenRecording"},
+    {AcceleratorAction::kSuspend, "Suspend"},
+    {AcceleratorAction::kSwapPrimaryDisplay, "SwapPrimaryDisplay"},
+    {AcceleratorAction::kSwitchIme, "SwitchIme"},
+    {AcceleratorAction::kSwitchToLastUsedIme, "SwitchToLastUsedIme"},
+    {AcceleratorAction::kSwitchToNextIme, "SwitchToNextIme"},
+    {AcceleratorAction::kSwitchToNextUser, "SwitchToNextUser"},
+    {AcceleratorAction::kSwitchToPreviousUser, "SwitchToPreviousUser"},
+    {AcceleratorAction::kTakePartialScreenshot, "TakePartialScreenshot"},
+    {AcceleratorAction::kTakeScreenshot, "TakeScreenshot"},
+    {AcceleratorAction::kTakeWindowScreenshot, "TakeWindowScreenshot"},
+    {AcceleratorAction::kToggleAppList, "ToggleAppList"},
+    {AcceleratorAction::kToggleCalendar, "ToggleCalendar"},
+    {AcceleratorAction::kToggleCapsLock, "ToggleCapsLock"},
+    {AcceleratorAction::kToggleClipboardHistory, "ToggleClipboardHistory"},
+    {AcceleratorAction::kToggleDockedMagnifier, "ToggleDockedMagnifier"},
+    {AcceleratorAction::kToggleFloating, "ToggleFloating"},
+    {AcceleratorAction::kToggleFullscreen, "ToggleFullscreen"},
+    {AcceleratorAction::kToggleFullscreenMagnifier,
+     "ToggleFullscreenMagnifier"},
+    {AcceleratorAction::kToggleGameDashboard, "ToggleGameDashboard"},
+    {AcceleratorAction::kToggleHighContrast, "ToggleHighContrast"},
+    {AcceleratorAction::kToggleMaximized, "ToggleMaximized"},
+    {AcceleratorAction::kToggleMessageCenterBubble,
+     "ToggleMessageCenterBubble"},
+    {AcceleratorAction::kToggleMirrorMode, "ToggleMirrorMode"},
+    {AcceleratorAction::kToggleMultitaskMenu, "ToggleMultitaskMenu"},
+    {AcceleratorAction::kToggleOverview, "ToggleOverview"},
+    {AcceleratorAction::kToggleProjectorMarker, "ToggleProjectorMarker"},
+    {AcceleratorAction::kToggleResizeLockMenu, "ToggleResizeLockMenu"},
+    {AcceleratorAction::kToggleSnapGroup, "ToggleSnapGroup"},
+    {AcceleratorAction::kToggleSnapGroupWindowsMinimizeAndRestore,
+     "ToggleSnapGroupWindowsMinimizeAndRestore"},
+    {AcceleratorAction::kToggleSpokenFeedback, "ToggleSpokenFeedback"},
+    {AcceleratorAction::kToggleStylusTools, "ToggleStylusTools"},
+    {AcceleratorAction::kToggleSystemTrayBubble, "ToggleSystemTrayBubble"},
+    {AcceleratorAction::kToggleWifi, "ToggleWifi"},
+    {AcceleratorAction::kTouchHudClear, "TouchHudClear"},
+    {AcceleratorAction::kTouchHudModeChange, "TouchHudModeChange"},
+    {AcceleratorAction::kTouchFingerprintSensor1, "TouchFingerprintSensor1"},
+    {AcceleratorAction::kTouchFingerprintSensor2, "TouchFingerprintSensor2"},
+    {AcceleratorAction::kTouchFingerprintSensor3, "TouchFingerprintSensor3"},
+    {AcceleratorAction::kUnpin, "Unpin"},
+    {AcceleratorAction::kVolumeDown, "VolumeDown"},
+    {AcceleratorAction::kVolumeMute, "VolumeMute"},
+    {AcceleratorAction::kVolumeUp, "VolumeUp"},
+    {AcceleratorAction::kWindowCycleSnapLeft, "WindowCycleSnapLeft"},
+    {AcceleratorAction::kWindowCycleSnapRight, "WindowCycleSnapRight"},
+    {AcceleratorAction::kWindowMinimize, "WindowMinimize"},
+    {AcceleratorAction::kMinimizeTopWindowOnBack, "MinimizeTopWindowOnBack"},
+    {AcceleratorAction::kVolumeMuteToggle, "VolumeMuteToggle"},
+    {AcceleratorAction::kTogglePicker, "TogglePicker"},
+    {AcceleratorAction::kAccessibilityAction, "AccessibilityAction"},
+    {AcceleratorAction::kEnableSelectToSpeak, "EnableSelectToSpeak"},
+    {AcceleratorAction::kTilingWindowResizeLeft, "TilingWindowResizeLeft"},
+    {AcceleratorAction::kTilingWindowResizeRight, "TilingWindowResizeRight"},
+    {AcceleratorAction::kTilingWindowResizeUp, "TilingWindowResizeUp"},
+    {AcceleratorAction::kTilingWindowResizeDown, "TilingWindowResizeDown"},
+    {AcceleratorAction::kToggleMouseKeys, "ToggleMouseKeys"},
+    {AcceleratorAction::kResizePipWindow, "ResizePipWindow"},
+    {AcceleratorAction::kToggleGeminiApp, "ToggleGeminiApp"},
+    {AcceleratorAction::kToggleDoNotDisturb, "ToggleDoNotDisturb"},
+    {AcceleratorAction::kToggleCameraAllowed, "ToggleCameraAllowed"},
+    {AcceleratorAction::kStartSunfishSession, "StartSunfishSession"},
+    {AcceleratorAction::kDebugClearUseKMeansPref, "DebugClearUseKMeansPref"},
+    {AcceleratorAction::kDebugKeyboardBacklightToggle,
+     "DebugKeyboardBacklightToggle"},
+    {AcceleratorAction::kDebugMicrophoneMuteToggle,
+     "DebugMicrophoneMuteToggle"},
+    {AcceleratorAction::kDebugPrintLayerHierarchy, "DebugPrintLayerHierarchy"},
+    {AcceleratorAction::kDebugPrintViewHierarchy, "DebugPrintViewHierarchy"},
+    {AcceleratorAction::kDebugPrintWindowHierarchy,
+     "DebugPrintWindowHierarchy"},
+    {AcceleratorAction::kDebugShowInformedRestore, "DebugShowInformedRestore"},
+    {AcceleratorAction::kDebugShowToast, "DebugShowToast"},
+    {AcceleratorAction::kDebugShowSystemNudge, "DebugShowSystemNudge"},
+    {AcceleratorAction::kDebugSystemUiStyleViewer, "DebugSystemUiStyleViewer"},
+    {AcceleratorAction::kDebugToggleDarkMode, "DebugToggleDarkMode"},
+    {AcceleratorAction::kDebugToggleDynamicColor, "DebugToggleDynamicColor"},
+    {AcceleratorAction::kDebugTogglePowerButtonMenu,
+     "DebugTogglePowerButtonMenu"},
+    {AcceleratorAction::kDebugToggleShowDebugBorders,
+     "DebugToggleShowDebugBorders"},
+    {AcceleratorAction::kDebugToggleShowFpsCounter,
+     "DebugToggleShowFpsCounter"},
+    {AcceleratorAction::kDebugToggleShowPaintRects,
+     "DebugToggleShowPaintRects"},
+    {AcceleratorAction::kDebugToggleTouchPad, "DebugToggleTouchPad"},
+    {AcceleratorAction::kDebugToggleTouchScreen, "DebugToggleTouchScreen"},
+    {AcceleratorAction::kDebugToggleTabletMode, "DebugToggleTabletMode"},
+    {AcceleratorAction::kDebugToggleVideoConferenceCameraTrayIcon,
+     "DebugToggleVideoConferenceCameraTrayIcon"},
+    {AcceleratorAction::kDebugToggleWallpaperMode, "DebugToggleWallpaperMode"},
+    {AcceleratorAction::kDebugTriggerCrash, "DebugTriggerCrash"},
+    {AcceleratorAction::kDebugToggleHudDisplay, "DebugToggleHudDisplay"},
+    {AcceleratorAction::kDebugToggleVirtualTrackpad,
+     "DebugToggleVirtualTrackpad"},
+    {AcceleratorAction::kDevAddRemoveDisplay, "DevAddRemoveDisplay"},
+    {AcceleratorAction::kDevToggleAppList, "DevToggleAppList"},
+    {AcceleratorAction::kDevToggleUnifiedDesktop, "DevToggleUnifiedDesktop"},
+    {AcceleratorAction::kDebugToggleFocusModeState,
+     "DebugToggleFocusModeState"},
+    {AcceleratorAction::kDebugStartSunfishSession, "DebugStartSunfishSession"},
+    {AcceleratorAction::kDebugShowTestWindow, "DebugShowTestWindow"},
+});
+
 const char* GetAcceleratorActionName(AcceleratorAction action) {
   // Define the mapping between an AcceleratorAction and its string name.
   // Example:
   //   AcceleratorAction::kDevToggleUnifiedDesktop -> "DevToggleUnifiedDesktop".
-  constexpr static auto kAcceleratorActionToName =
-      base::MakeFixedFlatMap<AcceleratorAction, const char*>({
-#define ACCELERATOR_ACTION_ENTRY(action) \
-  {AcceleratorAction::k##action, #action},
-#define ACCELERATOR_ACTION_ENTRY_FIXED_VALUE(action, value) \
-  {AcceleratorAction::k##action, #action},
-          ACCELERATOR_ACTIONS
-#undef ACCELERATOR_ACTION_ENTRY
-#undef ACCELERATOR_ACTION_ENTRY_FIXED_VALUE
-      });
   auto iter = kAcceleratorActionToName.find(action);
   CHECK(iter != kAcceleratorActionToName.end());
   return iter->second;
 }
 
+base::flat_set<AcceleratorAction> GetAcceleratorActionsForTest() {
+  base::flat_set<AcceleratorAction> all;
+  for (auto& entry : kAcceleratorActionToName) {
+    all.emplace(entry.first);
+  }
+  return all;
+}
+
 }  // namespace ash
diff --git a/ash/public/cpp/accelerator_actions.h b/ash/public/cpp/accelerator_actions.h
index ea26e712..181f08b 100644
--- a/ash/public/cpp/accelerator_actions.h
+++ b/ash/public/cpp/accelerator_actions.h
@@ -6,6 +6,7 @@
 #define ASH_PUBLIC_CPP_ACCELERATOR_ACTIONS_H_
 
 #include "ash/public/cpp/ash_public_export.h"
+#include "base/containers/flat_set.h"
 
 namespace ash {
 
@@ -29,202 +30,197 @@
 // The added enum member is kNewAction. Its string name is NewAction.
 //
 // LINT.IfChange
-#define ACCELERATOR_ACTIONS                                            \
-  ACCELERATOR_ACTION_ENTRY(BrightnessDown)                             \
-  ACCELERATOR_ACTION_ENTRY(BrightnessUp)                               \
-  ACCELERATOR_ACTION_ENTRY(CycleBackwardMru)                           \
-  ACCELERATOR_ACTION_ENTRY(CycleForwardMru)                            \
-  ACCELERATOR_ACTION_ENTRY(CycleSameAppWindowsBackward)                \
-  ACCELERATOR_ACTION_ENTRY(CycleSameAppWindowsForward)                 \
-  ACCELERATOR_ACTION_ENTRY(DesksActivateDeskLeft)                      \
-  ACCELERATOR_ACTION_ENTRY(DesksActivateDeskRight)                     \
-  ACCELERATOR_ACTION_ENTRY(DesksMoveActiveItemLeft)                    \
-  ACCELERATOR_ACTION_ENTRY(DesksMoveActiveItemRight)                   \
-  ACCELERATOR_ACTION_ENTRY(DesksNewDesk)                               \
-  ACCELERATOR_ACTION_ENTRY(DesksRemoveCurrentDesk)                     \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate0)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate1)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate2)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate3)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate4)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate5)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate6)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksActivate7)                             \
-  ACCELERATOR_ACTION_ENTRY(DesksToggleAssignToAllDesks)                \
-  ACCELERATOR_ACTION_ENTRY(DisableCapsLock)                            \
-  ACCELERATOR_ACTION_ENTRY(EnableOrToggleDictation)                    \
-  ACCELERATOR_ACTION_ENTRY(Exit)                                       \
-  ACCELERATOR_ACTION_ENTRY(FocusCameraPreview)                         \
-  ACCELERATOR_ACTION_ENTRY(FocusNextPane)                              \
-  ACCELERATOR_ACTION_ENTRY(FocusPreviousPane)                          \
-  ACCELERATOR_ACTION_ENTRY(FocusShelf)                                 \
-  ACCELERATOR_ACTION_ENTRY(FocusPip)                                   \
-  ACCELERATOR_ACTION_ENTRY(KeyboardBacklightToggle)                    \
-  ACCELERATOR_ACTION_ENTRY(KeyboardBrightnessDown)                     \
-  ACCELERATOR_ACTION_ENTRY(KeyboardBrightnessUp)                       \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp0)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp1)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp2)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp3)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp4)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp5)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp6)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchApp7)                                 \
-  ACCELERATOR_ACTION_ENTRY(LaunchLastApp)                              \
-  ACCELERATOR_ACTION_ENTRY(LockPressed)                                \
-  ACCELERATOR_ACTION_ENTRY(LockReleased)                               \
-  ACCELERATOR_ACTION_ENTRY(LockScreen)                                 \
-  ACCELERATOR_ACTION_ENTRY(MagnifierZoomIn)                            \
-  ACCELERATOR_ACTION_ENTRY(MagnifierZoomOut)                           \
-  ACCELERATOR_ACTION_ENTRY(MediaFastForward)                           \
-  ACCELERATOR_ACTION_ENTRY(MediaNextTrack)                             \
-  ACCELERATOR_ACTION_ENTRY(MediaPause)                                 \
-  ACCELERATOR_ACTION_ENTRY(MediaPlay)                                  \
-  ACCELERATOR_ACTION_ENTRY(MediaPlayPause)                             \
-  ACCELERATOR_ACTION_ENTRY(MediaPrevTrack)                             \
-  ACCELERATOR_ACTION_ENTRY(MediaRewind)                                \
-  ACCELERATOR_ACTION_ENTRY(MediaStop)                                  \
-  ACCELERATOR_ACTION_ENTRY(MicrophoneMuteToggle)                       \
-  ACCELERATOR_ACTION_ENTRY(MoveActiveWindowBetweenDisplays)            \
-  ACCELERATOR_ACTION_ENTRY(NewIncognitoWindow)                         \
-  ACCELERATOR_ACTION_ENTRY(NewTab)                                     \
-  ACCELERATOR_ACTION_ENTRY(NewWindow)                                  \
-  ACCELERATOR_ACTION_ENTRY(OpenCalculator)                             \
-  ACCELERATOR_ACTION_ENTRY(OpenCrosh)                                  \
-  ACCELERATOR_ACTION_ENTRY(OpenDiagnostics)                            \
-  ACCELERATOR_ACTION_ENTRY(OpenFeedbackPage)                           \
-  ACCELERATOR_ACTION_ENTRY(OpenFileManager)                            \
-  ACCELERATOR_ACTION_ENTRY(OpenGetHelp)                                \
-  /* Similar to kToggleClipboardHistory but is used to paste plain*/   \
-  /* text only when clipboard history menu is already open. */         \
-  ACCELERATOR_ACTION_ENTRY(PasteClipboardHistoryPlainText)             \
-  ACCELERATOR_ACTION_ENTRY(PowerPressed)                               \
-  ACCELERATOR_ACTION_ENTRY(PowerReleased)                              \
-  ACCELERATOR_ACTION_ENTRY(PrintUiHierarchies)                         \
-  ACCELERATOR_ACTION_ENTRY(PrivacyScreenToggle)                        \
-  ACCELERATOR_ACTION_ENTRY(RestoreTab)                                 \
-  ACCELERATOR_ACTION_ENTRY(RotateScreen)                               \
-  ACCELERATOR_ACTION_ENTRY(RotateWindow)                               \
-  ACCELERATOR_ACTION_ENTRY(ScaleUiDown)                                \
-  ACCELERATOR_ACTION_ENTRY(ScaleUiReset)                               \
-  ACCELERATOR_ACTION_ENTRY(ScaleUiUp)                                  \
-  ACCELERATOR_ACTION_ENTRY(ShowEmojiPicker)                            \
-  ACCELERATOR_ACTION_ENTRY(ToggleImeMenuBubble)                        \
-  ACCELERATOR_ACTION_ENTRY(ShowShortcutViewer)                         \
-  ACCELERATOR_ACTION_ENTRY(ShowTaskManager)                            \
-  ACCELERATOR_ACTION_ENTRY(StartAssistant)                             \
-  ACCELERATOR_ACTION_ENTRY(StopScreenRecording)                        \
-  ACCELERATOR_ACTION_ENTRY(Suspend)                                    \
-  ACCELERATOR_ACTION_ENTRY(SwapPrimaryDisplay)                         \
-  /* Switch to another IME depending on the accelerator. */            \
-  ACCELERATOR_ACTION_ENTRY(SwitchIme)                                  \
-  ACCELERATOR_ACTION_ENTRY(SwitchToLastUsedIme)                        \
-  ACCELERATOR_ACTION_ENTRY(SwitchToNextIme)                            \
-  ACCELERATOR_ACTION_ENTRY(SwitchToNextUser)                           \
-  ACCELERATOR_ACTION_ENTRY(SwitchToPreviousUser)                       \
-  ACCELERATOR_ACTION_ENTRY(TakePartialScreenshot)                      \
-  ACCELERATOR_ACTION_ENTRY(TakeScreenshot)                             \
-  ACCELERATOR_ACTION_ENTRY(TakeWindowScreenshot)                       \
-  ACCELERATOR_ACTION_ENTRY(ToggleAppList)                              \
-  ACCELERATOR_ACTION_ENTRY(ToggleCalendar)                             \
-  ACCELERATOR_ACTION_ENTRY(ToggleCapsLock)                             \
-  ACCELERATOR_ACTION_ENTRY(ToggleClipboardHistory)                     \
-  ACCELERATOR_ACTION_ENTRY(ToggleDockedMagnifier)                      \
-  ACCELERATOR_ACTION_ENTRY(ToggleFloating)                             \
-  ACCELERATOR_ACTION_ENTRY(ToggleFullscreen)                           \
-  ACCELERATOR_ACTION_ENTRY(ToggleFullscreenMagnifier)                  \
-  ACCELERATOR_ACTION_ENTRY(ToggleGameDashboard)                        \
-  ACCELERATOR_ACTION_ENTRY(ToggleHighContrast)                         \
-  ACCELERATOR_ACTION_ENTRY(ToggleMaximized)                            \
-  ACCELERATOR_ACTION_ENTRY(ToggleMessageCenterBubble)                  \
-  ACCELERATOR_ACTION_ENTRY(ToggleMirrorMode)                           \
-  ACCELERATOR_ACTION_ENTRY(ToggleMultitaskMenu)                        \
-  ACCELERATOR_ACTION_ENTRY(ToggleOverview)                             \
-  ACCELERATOR_ACTION_ENTRY(ToggleProjectorMarker)                      \
-  ACCELERATOR_ACTION_ENTRY(ToggleResizeLockMenu)                       \
-  ACCELERATOR_ACTION_ENTRY(ToggleSnapGroup)                            \
-  ACCELERATOR_ACTION_ENTRY(ToggleSnapGroupWindowsMinimizeAndRestore)   \
-  ACCELERATOR_ACTION_ENTRY(ToggleSpokenFeedback)                       \
-  ACCELERATOR_ACTION_ENTRY(ToggleStylusTools)                          \
-  ACCELERATOR_ACTION_ENTRY(ToggleSystemTrayBubble)                     \
-  ACCELERATOR_ACTION_ENTRY(ToggleWifi)                                 \
-  ACCELERATOR_ACTION_ENTRY(TouchHudClear)                              \
-  ACCELERATOR_ACTION_ENTRY(TouchHudModeChange)                         \
-  ACCELERATOR_ACTION_ENTRY(TouchFingerprintSensor1)                    \
-  ACCELERATOR_ACTION_ENTRY(TouchFingerprintSensor2)                    \
-  ACCELERATOR_ACTION_ENTRY(TouchFingerprintSensor3)                    \
-  ACCELERATOR_ACTION_ENTRY(Unpin)                                      \
-  ACCELERATOR_ACTION_ENTRY(VolumeDown)                                 \
-  ACCELERATOR_ACTION_ENTRY(VolumeMute)                                 \
-  ACCELERATOR_ACTION_ENTRY(VolumeUp)                                   \
-  ACCELERATOR_ACTION_ENTRY(WindowCycleSnapLeft)                        \
-  ACCELERATOR_ACTION_ENTRY(WindowCycleSnapRight)                       \
-  ACCELERATOR_ACTION_ENTRY(WindowMinimize)                             \
-  ACCELERATOR_ACTION_ENTRY(MinimizeTopWindowOnBack)                    \
-  ACCELERATOR_ACTION_ENTRY(VolumeMuteToggle)                           \
-  ACCELERATOR_ACTION_ENTRY(TogglePicker)                               \
-  ACCELERATOR_ACTION_ENTRY(AccessibilityAction)                        \
-  ACCELERATOR_ACTION_ENTRY(EnableSelectToSpeak)                        \
-  ACCELERATOR_ACTION_ENTRY(TilingWindowResizeLeft)                     \
-  ACCELERATOR_ACTION_ENTRY(TilingWindowResizeRight)                    \
-  ACCELERATOR_ACTION_ENTRY(TilingWindowResizeUp)                       \
-  ACCELERATOR_ACTION_ENTRY(TilingWindowResizeDown)                     \
-  ACCELERATOR_ACTION_ENTRY(ToggleMouseKeys)                            \
-  ACCELERATOR_ACTION_ENTRY(ResizePipWindow)                            \
-  ACCELERATOR_ACTION_ENTRY(ToggleGeminiApp)                            \
-  ACCELERATOR_ACTION_ENTRY(ToggleDoNotDisturb)                         \
-  ACCELERATOR_ACTION_ENTRY(ToggleCameraAllowed)                        \
-  ACCELERATOR_ACTION_ENTRY(StartSunfishSession)                        \
-  /* Debug actions are kept at an offset.*/                            \
-  /* This offset should be kept consistent with the enum*/             \
-  /* `AcceleratorAction` in*/                                          \
-  /* tools/metrics/histograms/metadata/chromeos/enums.xml */           \
-  ACCELERATOR_ACTION_ENTRY_FIXED_VALUE(DebugClearUseKMeansPref, 9000)  \
-  ACCELERATOR_ACTION_ENTRY(DebugKeyboardBacklightToggle)               \
-  ACCELERATOR_ACTION_ENTRY(DebugMicrophoneMuteToggle)                  \
-  ACCELERATOR_ACTION_ENTRY(DebugPrintLayerHierarchy)                   \
-  ACCELERATOR_ACTION_ENTRY(DebugPrintViewHierarchy)                    \
-  ACCELERATOR_ACTION_ENTRY(DebugPrintWindowHierarchy)                  \
-  ACCELERATOR_ACTION_ENTRY(DebugShowInformedRestore)                   \
-  ACCELERATOR_ACTION_ENTRY(DebugShowToast)                             \
-  ACCELERATOR_ACTION_ENTRY(DebugShowSystemNudge)                       \
-  ACCELERATOR_ACTION_ENTRY(DebugSystemUiStyleViewer)                   \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleDarkMode)                        \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleDynamicColor)                    \
-  ACCELERATOR_ACTION_ENTRY(DebugTogglePowerButtonMenu)                 \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleShowDebugBorders)                \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleShowFpsCounter)                  \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleShowPaintRects)                  \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleTouchPad)                        \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleTouchScreen)                     \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleTabletMode)                      \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleVideoConferenceCameraTrayIcon)   \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleWallpaperMode)                   \
-  /* Intentionally crash the ash process. */                           \
-  ACCELERATOR_ACTION_ENTRY(DebugTriggerCrash)                          \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleHudDisplay)                      \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleVirtualTrackpad)                 \
-  ACCELERATOR_ACTION_ENTRY(DevAddRemoveDisplay)                        \
-  /* Different than kToggleAppList to ignore search-as-modifier-key */ \
-  /* rules for enabling the accelerator. */                            \
-  ACCELERATOR_ACTION_ENTRY(DevToggleAppList)                           \
-  ACCELERATOR_ACTION_ENTRY(DevToggleUnifiedDesktop)                    \
-  ACCELERATOR_ACTION_ENTRY(DebugToggleFocusModeState)                  \
-  ACCELERATOR_ACTION_ENTRY(DebugStartSunfishSession)                   \
-  ACCELERATOR_ACTION_ENTRY(DebugShowTestWindow)                        \
-  // LINT.ThenChange(//ash/public/mojom/accelerator_actions.mojom)
-
 enum AcceleratorAction {
-#define ACCELERATOR_ACTION_ENTRY(action) k##action,
-#define ACCELERATOR_ACTION_ENTRY_FIXED_VALUE(action, value) k##action = value,
-  ACCELERATOR_ACTIONS
-#undef ACCELERATOR_ACTION_ENTRY
-#undef ACCELERATOR_ACTION_ENTRY_FIXED_VALUE
+  kBrightnessDown,
+  kBrightnessUp,
+  kCycleBackwardMru,
+  kCycleForwardMru,
+  kCycleSameAppWindowsBackward,
+  kCycleSameAppWindowsForward,
+  kDesksActivateDeskLeft,
+  kDesksActivateDeskRight,
+  kDesksMoveActiveItemLeft,
+  kDesksMoveActiveItemRight,
+  kDesksNewDesk,
+  kDesksRemoveCurrentDesk,
+  kDesksActivate0,
+  kDesksActivate1,
+  kDesksActivate2,
+  kDesksActivate3,
+  kDesksActivate4,
+  kDesksActivate5,
+  kDesksActivate6,
+  kDesksActivate7,
+  kDesksToggleAssignToAllDesks,
+  kDisableCapsLock,
+  kEnableOrToggleDictation,
+  kExit,
+  kFocusCameraPreview,
+  kFocusNextPane,
+  kFocusPreviousPane,
+  kFocusShelf,
+  kFocusPip,
+  kKeyboardBacklightToggle,
+  kKeyboardBrightnessDown,
+  kKeyboardBrightnessUp,
+  kLaunchApp0,
+  kLaunchApp1,
+  kLaunchApp2,
+  kLaunchApp3,
+  kLaunchApp4,
+  kLaunchApp5,
+  kLaunchApp6,
+  kLaunchApp7,
+  kLaunchLastApp,
+  kLockPressed,
+  kLockReleased,
+  kLockScreen,
+  kMagnifierZoomIn,
+  kMagnifierZoomOut,
+  kMediaFastForward,
+  kMediaNextTrack,
+  kMediaPause,
+  kMediaPlay,
+  kMediaPlayPause,
+  kMediaPrevTrack,
+  kMediaRewind,
+  kMediaStop,
+  kMicrophoneMuteToggle,
+  kMoveActiveWindowBetweenDisplays,
+  kNewIncognitoWindow,
+  kNewTab,
+  kNewWindow,
+  kOpenCalculator,
+  kOpenCrosh,
+  kOpenDiagnostics,
+  kOpenFeedbackPage,
+  kOpenFileManager,
+  kOpenGetHelp,
+  // Similar to kToggleClipboardHistory but is used to paste plain
+  // text only when clipboard history menu is already open.
+  kPasteClipboardHistoryPlainText,
+  kPowerPressed,
+  kPowerReleased,
+  kPrintUiHierarchies,
+  kPrivacyScreenToggle,
+  kRestoreTab,
+  kRotateScreen,
+  kRotateWindow,
+  kScaleUiDown,
+  kScaleUiReset,
+  kScaleUiUp,
+  kShowEmojiPicker,
+  kToggleImeMenuBubble,
+  kShowShortcutViewer,
+  kShowTaskManager,
+  kStartAssistant,
+  kStopScreenRecording,
+  kSuspend,
+  kSwapPrimaryDisplay,
+  // Switch to another IME depending on the accelerator.
+  kSwitchIme,
+  kSwitchToLastUsedIme,
+  kSwitchToNextIme,
+  kSwitchToNextUser,
+  kSwitchToPreviousUser,
+  kTakePartialScreenshot,
+  kTakeScreenshot,
+  kTakeWindowScreenshot,
+  kToggleAppList,
+  kToggleCalendar,
+  kToggleCapsLock,
+  kToggleClipboardHistory,
+  kToggleDockedMagnifier,
+  kToggleFloating,
+  kToggleFullscreen,
+  kToggleFullscreenMagnifier,
+  kToggleGameDashboard,
+  kToggleHighContrast,
+  kToggleMaximized,
+  kToggleMessageCenterBubble,
+  kToggleMirrorMode,
+  kToggleMultitaskMenu,
+  kToggleOverview,
+  kToggleProjectorMarker,
+  kToggleResizeLockMenu,
+  kToggleSnapGroup,
+  kToggleSnapGroupWindowsMinimizeAndRestore,
+  kToggleSpokenFeedback,
+  kToggleStylusTools,
+  kToggleSystemTrayBubble,
+  kToggleWifi,
+  kTouchHudClear,
+  kTouchHudModeChange,
+  kTouchFingerprintSensor1,
+  kTouchFingerprintSensor2,
+  kTouchFingerprintSensor3,
+  kUnpin,
+  kVolumeDown,
+  kVolumeMute,
+  kVolumeUp,
+  kWindowCycleSnapLeft,
+  kWindowCycleSnapRight,
+  kWindowMinimize,
+  kMinimizeTopWindowOnBack,
+  kVolumeMuteToggle,
+  kTogglePicker,
+  kAccessibilityAction,
+  kEnableSelectToSpeak,
+  kTilingWindowResizeLeft,
+  kTilingWindowResizeRight,
+  kTilingWindowResizeUp,
+  kTilingWindowResizeDown,
+  kToggleMouseKeys,
+  kResizePipWindow,
+  kToggleGeminiApp,
+  kToggleDoNotDisturb,
+  kToggleCameraAllowed,
+  kStartSunfishSession,
+  // Debug actions are kept at an offset.  This offset should be kept consistent
+  // with the enum `AcceleratorAction` in
+  // tools/metrics/histograms/metadata/chromeos/enums.xml
+  kDebugClearUseKMeansPref = 9000,
+  kDebugKeyboardBacklightToggle,
+  kDebugMicrophoneMuteToggle,
+  kDebugPrintLayerHierarchy,
+  kDebugPrintViewHierarchy,
+  kDebugPrintWindowHierarchy,
+  kDebugShowInformedRestore,
+  kDebugShowToast,
+  kDebugShowSystemNudge,
+  kDebugSystemUiStyleViewer,
+  kDebugToggleDarkMode,
+  kDebugToggleDynamicColor,
+  kDebugTogglePowerButtonMenu,
+  kDebugToggleShowDebugBorders,
+  kDebugToggleShowFpsCounter,
+  kDebugToggleShowPaintRects,
+  kDebugToggleTouchPad,
+  kDebugToggleTouchScreen,
+  kDebugToggleTabletMode,
+  kDebugToggleVideoConferenceCameraTrayIcon,
+  kDebugToggleWallpaperMode,
+  // Intentionally crash the ash process.
+  kDebugTriggerCrash,
+  kDebugToggleHudDisplay,
+  kDebugToggleVirtualTrackpad,
+  kDevAddRemoveDisplay,
+  // Different than kToggleAppList to ignore search-as-modifier-key
+  // rules for enabling the accelerator.
+  kDevToggleAppList,
+  kDevToggleUnifiedDesktop,
+  kDebugToggleFocusModeState,
+  kDebugStartSunfishSession,
+  kDebugShowTestWindow,
 };
+// LINT.ThenChange(//ash/public/mojom/accelerator_actions.mojom)
 
 ASH_PUBLIC_EXPORT const char* GetAcceleratorActionName(
     AcceleratorAction action);
 
+ASH_PUBLIC_EXPORT base::flat_set<AcceleratorAction>
+GetAcceleratorActionsForTest();
+
 }  // namespace ash
 
 #endif  // ASH_PUBLIC_CPP_ACCELERATOR_ACTIONS_H_
diff --git a/ash/public/cpp/accelerator_actions_unittest.cc b/ash/public/cpp/accelerator_actions_unittest.cc
index 4d56000..890656c 100644
--- a/ash/public/cpp/accelerator_actions_unittest.cc
+++ b/ash/public/cpp/accelerator_actions_unittest.cc
@@ -25,20 +25,6 @@
 constexpr char kAcceleratorActionsHash[] =
     "5376c379e20a43cf689c1d23bc111305426d078d0a24343e2fd4f63787c61ebc";
 
-// Define the mapping between an AcceleratorAction and its string name.
-// Example:
-//   AcceleratorAction::kDevToggleUnifiedDesktop -> "DevToggleUnifiedDesktop".
-constexpr static auto kAcceleratorActionToName =
-    base::MakeFixedFlatMap<AcceleratorAction, std::string_view>({
-#define ACCELERATOR_ACTION_ENTRY(action) \
-  {AcceleratorAction::k##action, #action},
-#define ACCELERATOR_ACTION_ENTRY_FIXED_VALUE(action, value) \
-  {AcceleratorAction::k##action, #action},
-        ACCELERATOR_ACTIONS
-#undef ACCELERATOR_ACTION_ENTRY
-#undef ACCELERATOR_ACTION_ENTRY_FIXED_VALUE
-    });
-
 struct TestParams {
   bool use_debug_shortcuts = false;
   bool use_dev_shortcuts = false;
@@ -80,14 +66,16 @@
   ASSERT_TRUE(enums);
   // The number of enums in the histogram entry should be equal to the number of
   // enums in the C++ file.
-  EXPECT_EQ(enums->size(), kAcceleratorActionToName.size());
+  EXPECT_EQ(enums->size(), GetAcceleratorActionsForTest().size());
 
   for (const auto& entry : *enums) {
     // Check that the C++ file has a definition equal to the histogram file.
-    EXPECT_EQ(entry.second, kAcceleratorActionToName.find(entry.first)->second)
+    AcceleratorAction action = static_cast<AcceleratorAction>(entry.first);
+    const char* action_name = GetAcceleratorActionName(action);
+    EXPECT_EQ(entry.second, action_name)
         << "Enum entry name: " << entry.second
-        << " in enums.xml is different from enum entry name: "
-        << kAcceleratorActionToName.find(entry.first)->second << " in C++ file";
+        << " in enums.xml is different from enum entry name: " << action_name
+        << " in C++ file";
   }
 }
 
@@ -100,12 +88,15 @@
       "`kDebugAcceleratorActionsNum` (if applicable).";
 
   // First check that the size of the enum is correct.
-  ASSERT_EQ(kAcceleratorActionToName.size(), kAcceleratorActionsTotalNum);
+  auto all = GetAcceleratorActionsForTest();
+  ASSERT_EQ(all.size(), kAcceleratorActionsTotalNum);
   const size_t kAcceleratorsToHashNum =
       kAcceleratorActionsTotalNum - kDebugAcceleratorActionsNum;
-  const std::string hash = ash::StableHashOfCollection(
-      base::span(kAcceleratorActionToName).first<kAcceleratorsToHashNum>(),
-      [](const auto& item) { return item.second; });
+  auto names = base::span(all).first<kAcceleratorsToHashNum>();
+  const std::string hash =
+      ash::StableHashOfCollection(names, [](const auto& action) {
+        return std::string(GetAcceleratorActionName(action));
+      });
 
   EXPECT_EQ(hash, kAcceleratorActionsHash)
       << kCommonMessage << " Please update kAcceleratorActionsHash to: \n"
diff --git a/ash/system/notification_center/message_center_utils.cc b/ash/system/notification_center/message_center_utils.cc
index def0bb0470..9b387aa9 100644
--- a/ash/system/notification_center/message_center_utils.cc
+++ b/ash/system/notification_center/message_center_utils.cc
@@ -111,7 +111,8 @@
         // `PrivacyIndicatorsTrayItemView` or `CameraMicTrayItemView` to show
         // indicators on the systray.
         if (notifier == kPrivacyIndicatorsNotifierId ||
-            notifier == kVmCameraMicNotifierId) {
+            notifier == kVmCameraMicNotifierId ||
+            notifier == kPrivacyIndicatorsMultiCaptureNotifierId) {
           return false;
         }
 
diff --git a/ash/system/unified/notification_icons_controller.cc b/ash/system/unified/notification_icons_controller.cc
index 73e92b51..a32fe7f 100644
--- a/ash/system/unified/notification_icons_controller.cc
+++ b/ash/system/unified/notification_icons_controller.cc
@@ -70,7 +70,8 @@
   if (notifier_id == kVmCameraMicNotifierId ||
       notifier_id == kBatteryNotificationNotifierId ||
       notifier_id == kUsbNotificationNotifierId ||
-      notifier_id == kPrivacyIndicatorsNotifierId) {
+      notifier_id == kPrivacyIndicatorsNotifierId ||
+      notifier_id == kPrivacyIndicatorsMultiCaptureNotifierId) {
     return false;
   }
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 909f163..d19540d 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1230,6 +1230,8 @@
       "android/yield_to_looper_checker.cc",
       "android/yield_to_looper_checker.h",
       "debug/stack_trace_android.cc",
+      "files/file_android.cc",
+      "files/file_android.h",
       "files/file_util_android.cc",
       "files/scoped_file_android.cc",
       "memory/platform_shared_memory_mapper_android.cc",
diff --git a/base/allocator/partition_allocator/partition_alloc.gni b/base/allocator/partition_allocator/partition_alloc.gni
index 6c26adec..38309da7 100644
--- a/base/allocator/partition_allocator/partition_alloc.gni
+++ b/base/allocator/partition_allocator/partition_alloc.gni
@@ -338,9 +338,9 @@
 }
 
 declare_args() {
-  # Shadow metadata is still under development and only supports Linux
-  # for now.
-  enable_shadow_metadata = false && is_linux && has_64_bit_pointers
+  # Because of address space issue, this feature cannot be enabled on
+  # 32bit OS and iOS, i.e. has_64_bit_pointers && !is_ios
+  move_metadata_outside_gigacage = false && has_64_bit_pointers && !is_ios
 }
 
 declare_args() {
diff --git a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
index 29341908..8eebbf6 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
+++ b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn
@@ -155,6 +155,7 @@
     "ENABLE_POINTER_ARITHMETIC_TRAIT_CHECK=$enable_pointer_arithmetic_trait_check",
     "ENABLE_POINTER_COMPRESSION=$enable_pointer_compression",
     "ENABLE_POINTER_SUBTRACTION_CHECK=$enable_pointer_subtraction_check",
+    "MOVE_METADATA_OUT_OF_GIGACAGE_FOR_64_BITS_POINTERS=$move_metadata_outside_gigacage",
     "ENABLE_THREAD_ISOLATION=$enable_pkeys",
     "EXPENSIVE_DCHECKS_ARE_ON=$enable_expensive_dchecks",
     "FORCE_DISABLE_BACKUP_REF_PTR_FEATURE=$force_disable_backup_ref_ptr_feature",
@@ -451,7 +452,6 @@
       "partition_page_constants.h",
       "partition_root.cc",
       "partition_root.h",
-      "partition_shared_mutex.h",
       "partition_stats.cc",
       "partition_stats.h",
       "partition_superpage_extent_entry.h",
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc
index 48f9b67..2d90e48 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.cc
@@ -33,7 +33,7 @@
 #include <windows.h>
 #endif  // PA_BUILDFLAG(IS_WIN)
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA) || PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
+#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
 #include <sys/mman.h>
 #endif
 
@@ -80,26 +80,37 @@
   }
 }
 
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR size_t
+MetadataInnerOffset(pool_handle pool) {
+  PA_DCHECK(kRegularPoolHandle <= pool && pool < kMaxPoolHandle);
+  // Each metadata needs 2 SystemPage, i.e. 1 SystemPage for Guardian
+  // and another SystemPage for actual metadata.
+  // To make the first SystemPage a guardian, need `+ 1`.
+  return SystemPageSize() * (2 * (pool - kRegularPoolHandle) + 1);
+}
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+
 }  // namespace
 
 PA_CONSTINIT PartitionAddressSpace::PoolSetup PartitionAddressSpace::setup_;
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-std::ptrdiff_t PartitionAddressSpace::regular_pool_shadow_offset_ = 0;
-std::ptrdiff_t PartitionAddressSpace::brp_pool_shadow_offset_ = 0;
-std::ptrdiff_t PartitionAddressSpace::configurable_pool_shadow_offset_ = 0;
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+PA_CONSTINIT std::array<std::ptrdiff_t, kMaxPoolHandle>
+    PartitionAddressSpace::offsets_to_metadata_ = {
+        0, 0, 0, 0,
+#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
+        0,
+#endif  // PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
+};
 
-// File descriptors for shared mappings.
-base::PlatformFile PartitionAddressSpace::regular_pool_fd_ =
-    base::kInvalidPlatformFile;
-base::PlatformFile PartitionAddressSpace::brp_pool_fd_ =
-    base::kInvalidPlatformFile;
-base::PlatformFile PartitionAddressSpace::configurable_pool_fd_ =
-    base::kInvalidPlatformFile;
-
-uintptr_t PartitionAddressSpace::pool_shadow_address_ =
+uintptr_t PartitionAddressSpace::metadata_region_start_ =
     PartitionAddressSpace::kUninitializedPoolBaseAddress;
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+
+#if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+size_t PartitionAddressSpace::metadata_region_size_ = 0;
+#endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 #if !PA_BUILDFLAG(IS_IOS)
@@ -139,16 +150,6 @@
 }
 #endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-size_t PartitionAddressSpace::CorePoolShadowSize() {
-  return CorePoolSize();
-}
-
-size_t PartitionAddressSpace::ConfigurablePoolShadowSize() {
-  return kConfigurablePoolMaxSize;
-}
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
-
 void PartitionAddressSpace::Init() {
   if (IsInitialized()) {
     return;
@@ -224,6 +225,10 @@
 #if PA_BUILDFLAG(ENABLE_POINTER_COMPRESSION)
   CompressedPointerBaseGlobal::SetBase(setup_.regular_pool_base_address_);
 #endif  // PA_BUILDFLAG(ENABLE_POINTER_COMPRESSION)
+
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  InitMetadataRegionAndOffsets();
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 }
 
 void PartitionAddressSpace::InitConfigurablePool(uintptr_t pool_base,
@@ -258,6 +263,21 @@
     WriteProtectThreadIsolatedGlobals(setup_.thread_isolation_);
   }
 #endif
+
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  // Initialize metadata for configurable pool without PartitionAlloc enabled.
+  // This will happen when there exists a test which uses configurable pool
+  // and a sanitizer is enabled.
+  if (metadata_region_start_ != kUninitializedPoolBaseAddress) {
+    // Set offset from ConfigurablePool to MetadataRegion.
+    offsets_to_metadata_[kConfigurablePoolHandle] =
+        metadata_region_start_ - ConfigurablePoolBase() +
+        MetadataInnerOffset(kConfigurablePoolHandle);
+  } else {
+    // If no metadata region is available, use `SystemPageSize()`.
+    offsets_to_metadata_[kConfigurablePoolHandle] = SystemPageSize();
+  }
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 }
 
 #if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
@@ -293,7 +313,11 @@
   PA_DCHECK(!IsInThreadIsolatedPool(setup_.thread_isolated_pool_base_address_ +
                                     pool_size));
 
-  // TODO(crbug.com/40238514): support PA_ENABLE_SHADOW_METADATA
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  offsets_to_metadata_[kThreadIsolatedPoolHandle] =
+      metadata_region_start_ - setup_.thread_isolated_pool_base_address_ +
+      MetadataInnerOffset(kThreadIsolatedPoolHandle);
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 }
 #endif  // PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
 
@@ -314,6 +338,17 @@
 #if PA_BUILDFLAG(ENABLE_POINTER_COMPRESSION)
   CompressedPointerBaseGlobal::ResetBaseForTesting();
 #endif  // PA_BUILDFLAG(ENABLE_POINTER_COMPRESSION)
+
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  FreePages(metadata_region_start_, MetadataRegionSize());
+  metadata_region_start_ = kUninitializedPoolBaseAddress;
+#if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+  metadata_region_size_ = 0;
+#endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+  for (size_t i = 0; i < kMaxPoolHandle; ++i) {
+    offsets_to_metadata_[i] = SystemPageSize();
+  }
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 }
 
 void PartitionAddressSpace::UninitConfigurablePoolForTesting() {
@@ -334,6 +369,9 @@
     WriteProtectThreadIsolatedGlobals(setup_.thread_isolation_);
   }
 #endif
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  offsets_to_metadata_[kConfigurablePoolHandle] = SystemPageSize();
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 }
 
 #if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
@@ -353,194 +391,42 @@
 }
 #endif
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-
-namespace {
-
-base::PlatformFile CreateAnonymousFileForMapping(
-    [[maybe_unused]] const char* name,
-    [[maybe_unused]] size_t size) {
-  base::PlatformFile fd = base::kInvalidPlatformFile;
-#if PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
-  // TODO(crbug.com/40238514): if memfd_secret() is available, try
-  // memfd_secret() first.
-  fd = memfd_create(name, MFD_CLOEXEC);
-  PA_CHECK(0 == ftruncate(fd, size));
-#else
-  // Not implemented yet.
-  PA_NOTREACHED();
-#endif  // PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
-  return fd;
-}
-
-}  // namespace
-
-void PartitionAddressSpace::InitShadowMetadata(PoolHandleMask mask) {
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+// Allocate virtual address space of metadata and initialize metadata offsets
+// of regular, brp and configurable pools.
+void PartitionAddressSpace::InitMetadataRegionAndOffsets() {
   // Set up an address space only once.
-  if (pool_shadow_address_ == kUninitializedPoolBaseAddress) {
-    // Reserve 1 address space for all pools.
-    const size_t shadow_pool_size =
-        std::max(ConfigurablePoolShadowSize(), CorePoolShadowSize());
-
-    // Reserve virtual address space for the shadow pool.
-    uintptr_t pool_shadow_address =
-        AllocPages(shadow_pool_size, PageAllocationGranularity(),
-                   PageAccessibilityConfiguration(
-                       PageAccessibilityConfiguration::kInaccessible),
-                   PageTag::kPartitionAlloc);
-    if (!pool_shadow_address) {
-      HandlePoolAllocFailure();
-    }
-
-    pool_shadow_address_ = pool_shadow_address;
+  if (metadata_region_start_ != kUninitializedPoolBaseAddress) {
+    return;
   }
 
-  // Set up a memory file for the given pool, and init |offset|.
-  if (ContainsFlags(mask, PoolHandleMask::kConfigurable)) {
-    if (configurable_pool_fd_ == base::kInvalidPlatformFile) {
-      PA_DCHECK(pool_shadow_address_);
-      PA_DCHECK(configurable_pool_shadow_offset_ == 0);
-      configurable_pool_fd_ = CreateAnonymousFileForMapping(
-          "configurable_pool_shadow", ConfigurablePoolShadowSize());
-      configurable_pool_shadow_offset_ =
-          pool_shadow_address_ - ConfigurablePoolBase() +
-          SystemPageSize() * kSystemPageOffsetOfConfigurablePoolShadow;
-    }
+#if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+  metadata_region_size_ = std::max(kConfigurablePoolMaxSize, CorePoolSize());
+#endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+
+  uintptr_t address =
+      AllocPages(MetadataRegionSize(), PageAllocationGranularity(),
+                 PageAccessibilityConfiguration(
+                     PageAccessibilityConfiguration::kInaccessible),
+                 PageTag::kPartitionAlloc);
+  if (!address) {
+    HandlePoolAllocFailure();
   }
-  if (ContainsFlags(mask, PoolHandleMask::kBRP)) {
-    if (brp_pool_fd_ == base::kInvalidPlatformFile) {
-      PA_DCHECK(pool_shadow_address_);
-      PA_DCHECK(brp_pool_shadow_offset_ == 0);
-      brp_pool_fd_ = CreateAnonymousFileForMapping("brp_pool_shadow",
-                                                   CorePoolShadowSize());
-      brp_pool_shadow_offset_ =
-          pool_shadow_address_ - BRPPoolBase() +
-          SystemPageSize() * kSystemPageOffsetOfBRPPoolShadow;
-    }
-  }
-  if (ContainsFlags(mask, PoolHandleMask::kRegular)) {
-    if (regular_pool_fd_ == base::kInvalidPlatformFile) {
-      PA_DCHECK(pool_shadow_address_);
-      PA_DCHECK(regular_pool_shadow_offset_ == 0);
-      regular_pool_fd_ = CreateAnonymousFileForMapping("regular_pool_shadow",
-                                                       CorePoolShadowSize());
-      regular_pool_shadow_offset_ =
-          pool_shadow_address_ - RegularPoolBase() +
-          SystemPageSize() * kSystemPageOffsetOfRegularPoolShadow;
-    }
-  }
+
+  metadata_region_start_ = address;
+
+  PA_DCHECK(RegularPoolBase() != kUninitializedPoolBaseAddress);
+  PA_DCHECK(BRPPoolBase() != kUninitializedPoolBaseAddress);
+
+  offsets_to_metadata_[kRegularPoolHandle] =
+      address - RegularPoolBase() + MetadataInnerOffset(kRegularPoolHandle);
+  offsets_to_metadata_[kBRPPoolHandle] =
+      address - BRPPoolBase() + MetadataInnerOffset(kBRPPoolHandle);
+
+  // ConfigurablePool has not been initialized yet at this time.
+  offsets_to_metadata_[kConfigurablePoolHandle] = SystemPageSize();
 }
-
-// Share a read-only metadata inside the given SuperPage with its writable
-// metadata.
-void PartitionAddressSpace::MapMetadata(uintptr_t super_page,
-                                        bool copy_metadata) {
-  PA_DCHECK(pool_shadow_address_);
-  PA_DCHECK(0u == (super_page & kSuperPageOffsetMask));
-  std::ptrdiff_t offset;
-  base::PlatformFile pool_fd = base::kInvalidPlatformFile;
-  uintptr_t base_address;
-
-  if (IsInRegularPool(super_page)) {
-    pool_fd = regular_pool_fd_;
-    offset = regular_pool_shadow_offset_;
-    base_address = RegularPoolBase();
-  } else if (IsInBRPPool(super_page)) {
-    offset = brp_pool_shadow_offset_;
-    pool_fd = brp_pool_fd_;
-    base_address = BRPPoolBase();
-  } else if (IsInConfigurablePool(super_page)) {
-    offset = configurable_pool_shadow_offset_;
-    pool_fd = configurable_pool_fd_;
-    base_address = ConfigurablePoolBase();
-  } else {
-    PA_NOTREACHED();
-  }
-
-  uintptr_t metadata = super_page + SystemPageSize();
-  size_t file_offset = (super_page - base_address) >> kSuperPageShift
-                                                          << SystemPageShift();
-
-#if PA_BUILDFLAG(IS_POSIX)
-  uintptr_t writable_metadata = metadata + offset;
-  void* ptr = mmap(reinterpret_cast<void*>(writable_metadata), SystemPageSize(),
-                   PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, pool_fd,
-                   file_offset);
-  PA_CHECK(ptr != MAP_FAILED);
-  PA_CHECK(ptr == reinterpret_cast<void*>(writable_metadata));
-
-  if (copy_metadata) [[unlikely]] {
-    // Copy the metadata from the private and copy-on-write page to
-    // the shared page. (=update the memory file)
-    memcpy(reinterpret_cast<void*>(writable_metadata),
-           reinterpret_cast<void*>(metadata), SystemPageSize());
-  }
-
-  ptr = mmap(reinterpret_cast<void*>(metadata), SystemPageSize(), PROT_READ,
-             MAP_FIXED | MAP_SHARED, pool_fd, file_offset);
-  PA_CHECK(ptr != MAP_FAILED);
-  PA_CHECK(ptr == reinterpret_cast<void*>(metadata));
-#else
-  // Not implemneted yet.
-  PA_NOTREACHED();
-#endif  // PA_BUILDFLAG(IS_POSIX)
-}
-
-// Regarding normal buckets, metadata will not be decommitted. However,
-// regarding direct-mapped, metadata will be decommitted (see UnmapNow()).
-// So shadow metadata must be also decommitted (including zero-initialization).
-void PartitionAddressSpace::UnmapShadowMetadata(uintptr_t super_page,
-                                                pool_handle pool) {
-  PA_DCHECK(0u == (super_page & kSuperPageOffsetMask));
-  std::ptrdiff_t offset;
-
-  switch (pool) {
-    case kRegularPoolHandle:
-      PA_DCHECK(RegularPoolBase() <= super_page);
-      PA_DCHECK((super_page - RegularPoolBase()) < CorePoolSize());
-      PA_DCHECK(IsShadowMetadataEnabled(kRegularPoolHandle));
-      offset = regular_pool_shadow_offset_;
-      break;
-    case kBRPPoolHandle:
-      PA_DCHECK(BRPPoolBase() <= super_page);
-      PA_DCHECK((super_page - BRPPoolBase()) < CorePoolSize());
-      PA_DCHECK(IsShadowMetadataEnabled(kBRPPoolHandle));
-      offset = brp_pool_shadow_offset_;
-      break;
-    case kConfigurablePoolHandle:
-      PA_DCHECK(IsShadowMetadataEnabled(kConfigurablePoolHandle));
-      offset = configurable_pool_shadow_offset_;
-      break;
-    default:
-      return;
-  }
-
-  uintptr_t writable_metadata = super_page + SystemPageSize() + offset;
-
-  void* ptr = reinterpret_cast<void*>(writable_metadata);
-
-  // When mapping the page again, we will use mmap() with MAP_FIXED |
-  // MAP_SHARED. Not with MAP_ANONYMOUS. If we don't clear the page here, the
-  // page will have the same content when re-mapped.
-  // TODO(crbug.com/40238514): Make PartitionAlloc not depend on that metadata
-  // pages have been already initialized to be zero. i.e. remove memset() below
-  // and make the constructors of SlotSpanMetadata, PartitionPageMetadata (and
-  // more struct/class if needed) initialize their members. Add test to check
-  // if the initialization is correctly done.
-  memset(ptr, 0, SystemPageSize());
-
-#if PA_BUILDFLAG(IS_POSIX)
-  void* ret = mmap(ptr, SystemPageSize(), PROT_NONE,
-                   MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-  PA_CHECK(ret != MAP_FAILED);
-  PA_CHECK(ret == ptr);
-#else
-  // Not implemented yet.
-  PA_NOTREACHED();
-#endif  // PA_BUILDFLAG(IS_POSIX)
-}
-
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
 #if defined(PARTITION_ALLOCATOR_CONSTANTS_POSIX_NONCONST_PAGE_SIZE)
 
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h
index 8e09f9c..581d3d5 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_address_space.h
@@ -233,11 +233,11 @@
     return (address & brp_pool_base_mask) == setup_.brp_pool_base_address_;
   }
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
   PA_ALWAYS_INLINE static uintptr_t BRPPoolBase() {
     return RegularPoolBase() + CorePoolSize();
   }
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
   // Checks whether the address belongs to either regular or BRP pool.
   // Returns false for nullptr.
@@ -286,108 +286,69 @@
   }
 #endif
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-  PA_ALWAYS_INLINE static bool IsShadowMetadataEnabledOnRegularPool() {
-    return regular_pool_fd_ != base::kInvalidPlatformFile;
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  // The MetadataRegionSize() returns the size of address space of metadata.
+  // The address space contains all metadata for all pools (i.e. regular, brp,
+  // and configurable pools).
+#if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+  PA_ALWAYS_INLINE static size_t MetadataRegionSize() {
+    return metadata_region_size_;
+  }
+#else
+  PA_ALWAYS_INLINE static constexpr size_t MetadataRegionSize() {
+    return std::max(kConfigurablePoolMaxSize, CorePoolSize());
+  }
+#endif
+
+  // Returns a metadata offset. SuperPage address plus the offset contains
+  // the metadata for the SuperPage.
+  PA_ALWAYS_INLINE static std::ptrdiff_t MetadataOffset(pool_handle pool) {
+    return offsets_to_metadata_[pool];
   }
 
-  PA_ALWAYS_INLINE static bool IsShadowMetadataEnabledOnBRPPool() {
-    return brp_pool_fd_ != base::kInvalidPlatformFile;
-  }
-
-  PA_ALWAYS_INLINE static bool IsShadowMetadataEnabledOnConfigurablePool() {
-    return configurable_pool_fd_ != base::kInvalidPlatformFile;
-  }
-
-  PA_ALWAYS_INLINE static bool IsShadowMetadataEnabled(pool_handle pool) {
-    switch (pool) {
-      case kRegularPoolHandle:
-        return IsShadowMetadataEnabledOnRegularPool();
-      case kBRPPoolHandle:
-        return IsShadowMetadataEnabledOnBRPPool();
-      case kConfigurablePoolHandle:
-        return IsShadowMetadataEnabledOnConfigurablePool();
-      default:
-        return false;
-    }
-  }
-
-  // To reduce the cost of address conversion (metadata address inside Regular
-  // Pool to its shadow metadata address), we will make the size of the address
-  // space of shadow metadata the same as `max(regular pool size, brp
-  // pool size, configurable pool size)` (only 1 shadow address space. Not 3)
-  // So we need to use different offset for metadata of the regular pool's
-  // SuperPages and for the brp pool's SuperPages.
-  // i.e. |kSystemPageOffsetOfRegularPoolShadow| and
-  // |kSystemPageOffsetOfBRPPoolShadow|.
-  //
-  // i: the index of SystemPage for metadata inside the regular pool's
-  // SuperPage.
-  //    (currently, the index is 1.)
-  //
-  //     i-th
-  // +------------+
-  // | SystemPage | (regular pool)
-  // +------------+
-  //       \
-  //        \ mapping
-  //         \
-  //      (i+kSystemPageOffsetOfRegularPoolShadow)-th
-  //     +------------+
-  //     | SystemPage | (shadow)
-  //     +------------+
-  //
-  // (i + kSystemPageOffsetOfRegularPoolShadow)-th SystemPage inside the matched
-  // SuperPage inside the shadow pool is used for the metadata.
-  static constexpr size_t kSystemPageOffsetOfRegularPoolShadow = 0u;
-  static constexpr size_t kSystemPageOffsetOfBRPPoolShadow = 2u;
-  static constexpr size_t kSystemPageOffsetOfConfigurablePoolShadow = 4u;
-
-  static size_t CorePoolShadowSize();
-  static size_t ConfigurablePoolShadowSize();
-
-  PA_ALWAYS_INLINE static std::ptrdiff_t RegularPoolShadowOffset() {
-    return regular_pool_shadow_offset_;
-  }
-
-  PA_ALWAYS_INLINE static std::ptrdiff_t BRPPoolShadowOffset() {
-    return brp_pool_shadow_offset_;
-  }
-
-  PA_ALWAYS_INLINE static std::ptrdiff_t ConfigurablePoolShadowOffset() {
-    return configurable_pool_shadow_offset_;
+  PA_ALWAYS_INLINE static std::ptrdiff_t MetadataOffsetFromAddr(
+      uintptr_t address) {
+    return MetadataOffset(GetPoolHandle(address));
   }
 
   // TODO(crbug.com/40238514): Confirm we can use kConfigurablePoolMaxSize/4
-  // for iOS and confirm iOS EarlyGrey tests pass when the shadow metadata
+  // for iOS and confirm iOS EarlyGrey tests pass when the external  metadata
   // is enabled, since IIRC iOS limits virtual address space too.
   static_assert(
       !PA_BUILDFLAG(IS_IOS),
       "kConfigurablePoolMaxSize is too large to run iOS EarlyGrey tests, "
       "because the test process cannot use an extended virtual address space. "
-      "Temporarily disable ShadowMetadata feature on iOS");
+      "Temporarily disable ExternalMetadata feature on iOS");
 
 #if PA_BUILDFLAG(DCHECKS_ARE_ON)
-  // Check whether the given |ptr| points to an address inside the address space
-  // reserved for the regular and brp shadow. However the result |true| doesn't
-  // mean the given |ptr| is valid. Because we don't use the entire address
-  // space for the shadow. We only use 2 SystemPageSize() / kSuperPageSize(%)
-  // of the space.
-  //
-  // TODO(crbug.com/40238514) This is an unused function. Start using it in
-  // tests and/or in production code.
-  PA_ALWAYS_INLINE static bool IsInPoolShadow(const void* ptr) {
-    uintptr_t ptr_as_uintptr = reinterpret_cast<uintptr_t>(ptr);
-    return (pool_shadow_address_ <= ptr_as_uintptr &&
-            (ptr_as_uintptr < pool_shadow_address_ + CorePoolSize() ||
-             ptr_as_uintptr < pool_shadow_address_ + kConfigurablePoolMaxSize));
+  PA_ALWAYS_INLINE static bool IsInMetadataRegion(uintptr_t address) {
+    return metadata_region_start_ <= address &&
+           address < metadata_region_start_ + MetadataRegionSize();
   }
 #endif  // PA_BUILDFLAG(DCHECKS_ARE_ON)
 
-  static void InitShadowMetadata(PoolHandleMask pool);
-  static void MapMetadata(uintptr_t super_page, bool copy_metadata);
-  static void UnmapShadowMetadata(uintptr_t super_page, pool_handle pool);
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+  PA_ALWAYS_INLINE static pool_handle GetPoolHandle(uintptr_t address) {
+#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
+    if (IsInBRPPool(address)) [[likely]] {
+      return kBRPPoolHandle;
+    }
+#endif
+    if (IsInRegularPool(address)) [[likely]] {
+      return kRegularPoolHandle;
+    }
+    if (IsInConfigurablePool(address)) {
+      return kConfigurablePoolHandle;
+    }
+#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
+    if (IsInThreadIsolatedPool(address)) {
+      return kThreadIsolatedPoolHandle;
+    }
+#endif
+    return kNullPoolHandle;
+  }
+
+  static void InitMetadataRegionAndOffsets();
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
   // PartitionAddressSpace is static_only class.
   PartitionAddressSpace() = delete;
@@ -525,15 +486,13 @@
   // alignment and padding.
   PA_CONSTINIT static PoolSetup setup_;
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-  static std::ptrdiff_t regular_pool_shadow_offset_;
-  static std::ptrdiff_t brp_pool_shadow_offset_;
-  static std::ptrdiff_t configurable_pool_shadow_offset_;
-  static base::PlatformFile regular_pool_fd_;
-  static base::PlatformFile brp_pool_fd_;
-  static base::PlatformFile configurable_pool_fd_;
-  static uintptr_t pool_shadow_address_;
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  static std::array<std::ptrdiff_t, kMaxPoolHandle> offsets_to_metadata_;
+  static uintptr_t metadata_region_start_;
+#if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+  static size_t metadata_region_size_;
+#endif  // PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
 #if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
   // If we use thread isolation, we need to write-protect its metadata.
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time_win.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time_win.cc
index b68e825..bf37a99 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time_win.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/time/time_win.cc
@@ -422,7 +422,8 @@
   ::GetThreadTimes(thread_handle.platform_handle(), &creation_time, &exit_time,
                    &kernel_time, &user_time);
 
-  const int64_t us = FileTimeToMicroseconds(user_time);
+  const int64_t us =
+      FileTimeToMicroseconds(user_time) + FileTimeToMicroseconds(kernel_time);
 #else
   // Get the number of TSC ticks used by the current thread.
   ULONG64 thread_cycle_time = 0;
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h
index a847f6a7..d81b534b 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h
@@ -172,9 +172,18 @@
 // differently with 32-bits pointers (see glossary).
 #define PA_CONFIG_ENABLE_SHADOW_METADATA() 0
 
+#if PA_BUILDFLAG(MOVE_METADATA_OUT_OF_GIGACAGE_FOR_64_BITS_POINTERS) && \
+    PA_BUILDFLAG(HAS_64_BIT_POINTERS)
+#define PA_CONFIG_MOVE_METADATA_OUT_OF_GIGACAGE() 1
+#else
+#define PA_CONFIG_MOVE_METADATA_OUT_OF_GIGACAGE() 0
+#endif
+
 // PartitionAlloc uses PartitionRootEnumerator to acquire all
 // PartitionRoots at BeforeFork and to release at AfterFork.
-#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_CONFIG(HAS_ATFORK_HANDLER)
+#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
+        PA_CONFIG(HAS_ATFORK_HANDLER) ||           \
+    PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 #define PA_CONFIG_USE_PARTITION_ROOT_ENUMERATOR() 1
 #else
 #define PA_CONFIG_USE_PARTITION_ROOT_ENUMERATOR() 0
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_perftest.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_perftest.cc
index 716d86a9..261013b1 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_perftest.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_perftest.cc
@@ -460,13 +460,6 @@
 
 class PartitionAllocMemoryAllocationPerfTest
     : public testing::TestWithParam<std::tuple<int, AllocatorType>> {
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-  void SetUp() override {
-    PartitionRoot::EnableShadowMetadata(
-        partition_alloc::internal::PoolHandleMask::kRegular |
-        partition_alloc::internal::PoolHandleMask::kBRP);
-  }
-#endif
 };
 
 // Only one partition with a thread cache: cannot use the thread cache when
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc
index a22da39..2e7e6b3 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_unittest.cc
@@ -467,10 +467,6 @@
     PartitionRoot::SetSortActiveSlotSpansEnabled(true);
     PartitionAllocGlobalInit(HandleOOM);
     InitializeMainTestAllocators();
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-    PartitionRoot::EnableShadowMetadata(internal::PoolHandleMask::kRegular |
-                                        internal::PoolHandleMask::kBRP);
-#endif
 
     test_bucket_index_ = SizeToIndex(ActualTestAllocSize());
   }
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc
index f35907b..523148f0 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_bucket.cc
@@ -218,18 +218,6 @@
   PartitionPageMetadata* page_metadata = nullptr;
 
   {
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-    // Because of the performance reason, PartitionRoot's lock is unlocked
-    // here. However this causes multi-thread issue when running
-    // EnableShadowMetadata(). If some thread is running PartitionDirectMap()
-    // and unlock PartitionRoot lock and also another thread is running
-    // EnableShadowMetadata(), the metadata page's permission will be modified
-    // by both threads and chrome will crash. c.f. crbug.com/378809882
-    // Be careful. This should not block PartitionDirectMap() in another thread.
-    internal::SharedLock shared_lock(
-        PartitionRoot::g_shadow_metadata_init_mutex_);
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
-
     // Getting memory for direct-mapped allocations doesn't interact with the
     // rest of the allocator, but takes a long time, as it involves several
     // system calls. Although no mmap() (or equivalent) calls are made on
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
index db43f384..7b39cd6 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.cc
@@ -27,7 +27,6 @@
 #include "partition_alloc/partition_cookie.h"
 #include "partition_alloc/partition_oom.h"
 #include "partition_alloc/partition_page.h"
-#include "partition_alloc/partition_superpage_extent_entry.h"
 #include "partition_alloc/reservation_offset_table.h"
 #include "partition_alloc/spinning_mutex.h"
 #include "partition_alloc/tagging.h"
@@ -49,16 +48,13 @@
 
 #if PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
 #include <pthread.h>
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-#include <sys/mman.h>
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
 #endif  // PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
 
 namespace partition_alloc::internal {
 
 #if PA_BUILDFLAG(RECORD_ALLOC_INFO)
-// Even if this is not hidden behind a PA_BUILDFLAG, it should not use any
-// memory when recording is disabled, since it ends up in the .bss section.
+// Even if this is not hidden behind a BUILDFLAG, it should not use any memory
+// when recording is disabled, since it ends up in the .bss section.
 AllocInfo g_allocs = {};
 
 void RecordAllocOrFree(uintptr_t addr, size_t size) {
@@ -82,7 +78,7 @@
   // Zero it just in case, to catch errors.
   orig_address = 0;
 
-  auto* slot_span = internal::SlotSpanMetadata::FromSlotStart(slot_start);
+  auto* slot_span = SlotSpanMetadata::FromSlotStart(slot_start);
   auto* root = PartitionRoot::FromSlotSpanMetadata(slot_span);
   // Double check that in-slot metadata is indeed present. Currently that's the
   // case only when BRP is used.
@@ -108,10 +104,6 @@
 
 namespace partition_alloc {
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-internal::SharedMutex PartitionRoot::g_shadow_metadata_init_mutex_;
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
-
 #if PA_CONFIG(USE_PARTITION_ROOT_ENUMERATOR)
 
 namespace {
@@ -210,9 +202,7 @@
 
 #endif  // PA_USE_PARTITION_ROOT_ENUMERATOR
 
-#if (PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-     PA_CONFIG(HAS_ATFORK_HANDLER)) ||              \
-    PA_CONFIG(ENABLE_SHADOW_METADATA)
+#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_CONFIG(HAS_ATFORK_HANDLER)
 
 namespace {
 
@@ -238,9 +228,8 @@
 }
 
 }  // namespace
-
-#endif  // (PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
-        // PA_CONFIG(HAS_ATFORK_HANDLER)) || PA_CONFIG(ENABLE_SHADOW_METADATA)
+#endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
+        // PA_CONFIG(HAS_ATFORK_HANDLER)
 
 #if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
@@ -251,8 +240,8 @@
 // PA_NO_THREAD_SAFETY_ANALYSIS: acquires the lock and doesn't release it, by
 // design.
 void BeforeForkInParent() PA_NO_THREAD_SAFETY_ANALYSIS {
-  //  PartitionRoot::GetLock() is private. So use
-  //  g_root_enumerator_lock here.
+  // PartitionRoot::GetLock() is private. So use
+  // g_root_enumerator_lock here.
   g_root_enumerator_lock.Acquire();
   internal::PartitionRootEnumerator::Instance().Enumerate(
       LockRoot, false,
@@ -346,71 +335,6 @@
 
 #endif  // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-namespace {
-
-void MakeSuperPageExtentEntriesShared(PartitionRoot* root,
-                                      internal::PoolHandleMask mask)
-    PA_NO_THREAD_SAFETY_ANALYSIS {
-  PA_DCHECK(root);
-  // Regardless of root->ChoosePool(), no chance if shadow_pool_offset_ is
-  // non-zero.
-  if (root->settings.shadow_pool_offset_) {
-    return;
-  }
-
-  switch (root->ChoosePool()) {
-    case internal::kRegularPoolHandle:
-      if (!ContainsFlags(mask, internal::PoolHandleMask::kRegular)) {
-        return;
-      }
-      root->settings.shadow_pool_offset_ =
-          internal::PartitionAddressSpace::RegularPoolShadowOffset();
-      break;
-    case internal::kBRPPoolHandle:
-      if (!ContainsFlags(mask, internal::PoolHandleMask::kBRP)) {
-        return;
-      }
-      root->settings.shadow_pool_offset_ =
-          internal::PartitionAddressSpace::BRPPoolShadowOffset();
-      break;
-    case internal::kConfigurablePoolHandle:
-      if (!ContainsFlags(mask, internal::PoolHandleMask::kConfigurable)) {
-        return;
-      }
-      root->settings.shadow_pool_offset_ =
-          internal::PartitionAddressSpace::ConfigurablePoolShadowOffset();
-      break;
-    default:
-      return;
-  }
-
-  // For normal-bucketed.
-  for (const internal::PartitionSuperPageExtentEntry* extent =
-           root->first_extent;
-       extent != nullptr; extent = extent->next) {
-    //  The page which contains the extent is in-used and shared mapping.
-    uintptr_t super_page = SuperPagesBeginFromExtent(extent);
-    for (size_t i = 0; i < extent->number_of_consecutive_super_pages; ++i) {
-      internal::PartitionAddressSpace::MapMetadata(super_page,
-                                                   /*copy_metadata=*/true);
-      super_page += kSuperPageSize;
-    }
-    PA_DCHECK(extent->root == root);
-  }
-
-  // For direct-mapped.
-  for (const internal::PartitionDirectMapExtent* extent = root->direct_map_list;
-       extent != nullptr; extent = extent->next_extent) {
-    internal::PartitionAddressSpace::MapMetadata(
-        reinterpret_cast<uintptr_t>(extent) & internal::kSuperPageBaseMask,
-        /*copy_metadata=*/true);
-  }
-}
-
-}  // namespace
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
-
 namespace internal {
 
 namespace {
@@ -803,10 +727,10 @@
     PA_EXCLUSIVE_LOCKS_REQUIRED(internal::PartitionRootLock(root)) {
   PA_DCHECK(!bucket->is_direct_mapped());
   stats_out->is_valid = false;
-  // If the active slot span list is empty (==internal::SlotSpanMetadata::
-  // get_sentinel_slot_span()),
-  // the bucket might still need to be reported if it has a list of empty,
-  // decommitted or full slot spans.
+  // If the active slot span list is empty (==
+  // internal::SlotSpanMetadata::get_sentinel_slot_span()), the bucket might
+  // still need to be reported if it has a list of empty, decommitted or full
+  // slot spans.
   if (bucket->active_slot_spans_head ==
           internal::SlotSpanMetadata::get_sentinel_slot_span() &&
       !bucket->empty_slot_spans_head && !bucket->decommitted_slot_spans_head &&
@@ -855,13 +779,13 @@
 void DCheckIfManagedByPartitionAllocBRPPool(uintptr_t address) {
   PA_DCHECK(IsManagedByPartitionAllocBRPPool(address));
 }
-#endif  // PA_BUILDFLAG(DCHECKS_ARE_ON)
+#endif
 
 #if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
 void PartitionAllocThreadIsolationInit(ThreadIsolationOption thread_isolation) {
 #if PA_BUILDFLAG(DCHECKS_ARE_ON)
   ThreadIsolationSettings::settings.enabled = true;
-#endif  // PA_BUILDFLAG(DCHECKS_ARE_ON)
+#endif
   PartitionAddressSpace::InitThreadIsolatedPool(thread_isolation);
   // Call WriteProtectThreadIsolatedGlobals last since we might not have write
   // permissions to to globals afterwards.
@@ -971,20 +895,13 @@
 #endif
       internal::AddressPoolManager::GetInstance().UnreserveAndDecommit(
           pool_handle, address, size);
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-      if (internal::PartitionAddressSpace::IsShadowMetadataEnabled(
-              pool_handle)) {
-        internal::PartitionAddressSpace::UnmapShadowMetadata(address,
-                                                             pool_handle);
-      }
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
       curr = next;
     }
     first_extent = current_extent = nullptr;
   }
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
   // Decommit direct-mapped allocations too.
-  if (internal::PartitionAddressSpace::IsShadowMetadataEnabled(pool_handle)) {
+  {
     auto* curr = direct_map_list;
     while (curr != nullptr) {
       auto* next = curr->next_extent;
@@ -999,17 +916,13 @@
           pool_handle, reservation_start, reservation_size);
 #endif  // !PA_BUILDFLAG(HAS_64_BIT_POINTERS)
 
-      // After resetting the table entries, unreserve and decommit the memory.
       internal::AddressPoolManager::GetInstance().UnreserveAndDecommit(
           pool_handle, reservation_start, reservation_size);
-
-      internal::PartitionAddressSpace::UnmapShadowMetadata(reservation_start,
-                                                           pool_handle);
       curr = next;
     }
     direct_map_list = nullptr;
   }
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 }
 
 #if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && \
@@ -1205,27 +1118,10 @@
     internal::PartitionRootEnumerator::Instance().Register(this);
 #endif
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-    if (internal::PartitionAddressSpace::IsShadowMetadataEnabled(
-            settings.pool_handle)) {
-      switch (settings.pool_handle) {
-        case internal::kRegularPoolHandle:
-          settings.shadow_pool_offset_ =
-              internal::PartitionAddressSpace::RegularPoolShadowOffset();
-          break;
-        case internal::kBRPPoolHandle:
-          settings.shadow_pool_offset_ =
-              internal::PartitionAddressSpace::BRPPoolShadowOffset();
-          break;
-        case internal::kConfigurablePoolHandle:
-          settings.shadow_pool_offset_ =
-              internal::PartitionAddressSpace::ConfigurablePoolShadowOffset();
-          break;
-        default:
-          break;
-      }
-    }
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+    settings.metadata_offset_ =
+        internal::PartitionAddressSpace::MetadataOffset(settings.pool_handle);
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
     initialized = true;
   }
@@ -1286,10 +1182,12 @@
 bool PartitionRoot::TryReallocInPlaceForDirectMap(
     internal::SlotSpanMetadata* slot_span,
     size_t requested_size) {
+#if PA_BUILDFLAG(DCHECKS_ARE_ON)
   PA_DCHECK(slot_span->bucket->is_direct_mapped());
   // Slot-span metadata isn't MTE-tagged.
   PA_DCHECK(GetReservationOffsetTable().IsManagedByDirectMap(
       reinterpret_cast<uintptr_t>(slot_span)));
+#endif
 
   size_t raw_size = AdjustSizeForExtrasAdd(requested_size);
   auto* extent = DirectMapExtent::FromSlotSpanMetadata(slot_span);
@@ -1380,14 +1278,7 @@
   DecreaseTotalSizeOfAllocatedBytes(reinterpret_cast<uintptr_t>(slot_span),
                                     slot_span->bucket->slot_size);
   slot_span->SetRawSize(raw_size);
-#if !PA_CONFIG(ENABLE_SHADOW_METADATA)
   slot_span->bucket->slot_size = new_slot_size;
-#else
-  internal::PartitionBucket* writable_bucket =
-      reinterpret_cast<internal::PartitionBucket*>(
-          reinterpret_cast<intptr_t>(slot_span->bucket) + ShadowPoolOffset());
-  writable_bucket->slot_size = new_slot_size;
-#endif  // !PA_CONFIG(ENABLE_SHADOW_METADATA)
   IncreaseTotalSizeOfAllocatedBytes(reinterpret_cast<uintptr_t>(slot_span),
                                     slot_span->bucket->slot_size, raw_size);
 
@@ -1906,38 +1797,6 @@
 #endif  // PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
 
 // static
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-void PartitionRoot::EnableShadowMetadata(internal::PoolHandleMask mask) {
-#if PA_BUILDFLAG(IS_LINUX)
-  // TODO(crbug.com/40238514): implement ModuleCache() or something to
-  // load required shared libraries in advance.
-  // Since memfd_create() causes dlsym(), it is not possible to invoke
-  // memfd_create() while PartitionRoot-s are locked.
-  // So invoke memfd_create() here and invoke dysym() in advance.
-  // This is required to enable ShadowMetadata on utility processes.
-  { close(memfd_create("module_cache", MFD_CLOEXEC)); }
-#endif
-  internal::UniqueLock unique_lock(g_shadow_metadata_init_mutex_);
-
-  internal::ScopedGuard guard(g_root_enumerator_lock);
-  // Must lock all PartitionRoot-s and ThreadCache.
-  internal::PartitionRootEnumerator::Instance().Enumerate(
-      LockRoot, false,
-      internal::PartitionRootEnumerator::EnumerateOrder::kNormal);
-  {
-    internal::ScopedGuard thread_cache_guard(ThreadCacheRegistry::GetLock());
-    internal::PartitionAddressSpace::InitShadowMetadata(mask);
-    internal::PartitionRootEnumerator::Instance().Enumerate(
-        MakeSuperPageExtentEntriesShared, mask,
-        internal::PartitionRootEnumerator::EnumerateOrder::kNormal);
-  }
-  internal::PartitionRootEnumerator::Instance().Enumerate(
-      UnlockOrReinitRoot, false,
-      internal::PartitionRootEnumerator::EnumerateOrder::kReverse);
-}
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
-
-// static
 void PartitionRoot::CheckMetadataIntegrity(const void* ptr) {
   uintptr_t address = internal::ObjectInnerPtr2Addr(ptr);
   if (!IsManagedByPartitionAlloc(address)) {
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
index 7ed5712..0037cb1 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_root.h
@@ -69,7 +69,6 @@
 #include "partition_alloc/partition_lock.h"
 #include "partition_alloc/partition_oom.h"
 #include "partition_alloc/partition_page.h"
-#include "partition_alloc/partition_shared_mutex.h"
 #include "partition_alloc/reservation_offset_table.h"
 #include "partition_alloc/scheduler_loop_quarantine.h"
 #include "partition_alloc/tagging.h"
@@ -289,8 +288,8 @@
     static inline constexpr uint32_t extras_size = 0;
 #endif  // PA_CONFIG(EXTRAS_REQUIRED)
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-    std::ptrdiff_t shadow_pool_offset_ = 0;
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+    std::ptrdiff_t metadata_offset_ = 0;
 #endif
   };
 
@@ -397,12 +396,6 @@
   internal::base::TimeTicks (*now_maybe_overridden_for_testing)() =
       internal::base::TimeTicks::Now;
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-  // Locks not to run EnableShadowMetadata() and PartitionDirectMap()
-  // at the same time.
-  static internal::SharedMutex g_shadow_metadata_init_mutex_;
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
-
   PartitionRoot();
   explicit PartitionRoot(PartitionOptions opts);
 
@@ -870,19 +863,15 @@
         scheduler_loop_quarantine_root, config);
   }
 
-#if PA_CONFIG(ENABLE_SHADOW_METADATA)
-  // TODO(crbug.com/40238514) This is an unused function. Start using it in
-  // tests and/or in production code.
-  static void EnableShadowMetadata(internal::PoolHandleMask mask);
-
-  PA_ALWAYS_INLINE std::ptrdiff_t ShadowPoolOffset() const {
-    return settings.shadow_pool_offset_;
+#if PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
+  PA_ALWAYS_INLINE std::ptrdiff_t MetadataOffset() const {
+    return settings.metadata_offset_;
   }
 #else
-  PA_ALWAYS_INLINE constexpr std::ptrdiff_t ShadowPoolOffset() const {
-    return 0;
-  }
-#endif  // PA_CONFIG(ENABLE_SHADOW_METADATA)
+  PA_ALWAYS_INLINE
+  PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR
+  size_t MetadataOffset() const { return internal::SystemPageSize(); }
+#endif  // PA_CONFIG(MOVE_METADATA_OUT_OF_GIGACAGE)
 
   PA_NOINLINE static void CheckMetadataIntegrity(const void* object);
 
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_shared_mutex.h b/base/allocator/partition_allocator/src/partition_alloc/partition_shared_mutex.h
deleted file mode 100644
index 46cbc102..0000000
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_shared_mutex.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef PARTITION_ALLOC_PARTITION_SHARED_MUTEX_H_
-#define PARTITION_ALLOC_PARTITION_SHARED_MUTEX_H_
-
-#include "partition_alloc/partition_alloc_base/thread_annotations.h"
-#include "partition_alloc/partition_lock.h"
-
-namespace partition_alloc::internal {
-
-// A partial implementation of `std::shared_mutex` for PartitionAllocator.
-// Since `std::shared_mutex` allocates memory, we cannot use it inside
-// PartitionAllocator. The difference between `std::shared_mutex` and this
-// SharedMutex, this SharedMutex doesn't support try_lock() and
-// try_lock_shared(), because no code uses the methods.
-class PA_LOCKABLE SharedMutex {
- public:
-  inline constexpr SharedMutex() = default;
-
-  void lock() PA_EXCLUSIVE_LOCK_FUNCTION() { writer_lock_.Acquire(); }
-
-  void unlock() PA_UNLOCK_FUNCTION() { writer_lock_.Release(); }
-
-  void lock_shared() PA_SHARED_LOCK_FUNCTION() {
-    ScopedGuard lock(reader_lock_);
-    ++counter_;
-    if (counter_ == 1u) {
-      writer_lock_.Acquire();
-    }
-  }
-
-  void unlock_shared() PA_UNLOCK_FUNCTION() {
-    ScopedGuard lock(reader_lock_);
-    --counter_;
-    if (counter_ == 0u) {
-      writer_lock_.Release();
-    }
-  }
-
- private:
-  Lock reader_lock_;
-  Lock writer_lock_;
-  size_t counter_ PA_GUARDED_BY(reader_lock_) = 0;
-};
-
-static_assert(std::is_trivially_destructible_v<SharedMutex>,
-              "SharedMutex must be trivally destructible.");
-
-// A partial implementation of `std::unique_lock` for PartitionAllocator.
-// Locking a UniqueLock locks the associated shared mutex in exclusive mode.
-class PA_SCOPED_LOCKABLE UniqueLock {
- public:
-  explicit UniqueLock(SharedMutex& mutex) PA_EXCLUSIVE_LOCK_FUNCTION(mutex)
-      : mutex_(mutex) {
-    mutex_.lock();
-  }
-  ~UniqueLock() PA_UNLOCK_FUNCTION() { mutex_.unlock(); }
-
- private:
-  SharedMutex& mutex_;
-};
-
-// A partial implementation of `std::shared_lock` for PartitionAllocator.
-// Locking a SharedLock locks the associated shared mutex in shared mode.
-// (like std::shared_lock).
-class PA_SCOPED_LOCKABLE SharedLock {
- public:
-  explicit SharedLock(SharedMutex& mutex) PA_SHARED_LOCK_FUNCTION(mutex)
-      : mutex_(mutex) {
-    mutex_.lock_shared();
-  }
-  ~SharedLock() PA_UNLOCK_FUNCTION() { mutex_.unlock_shared(); }
-
- private:
-  SharedMutex& mutex_;
-};
-
-}  // namespace partition_alloc::internal
-
-#endif  // PARTITION_ALLOC_PARTITION_SHARED_MUTEX_H_
diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc
index 59bc6cc..a1cb71c9 100644
--- a/base/android/content_uri_utils.cc
+++ b/base/android/content_uri_utils.cc
@@ -40,6 +40,8 @@
 
   switch (open_flags) {
     case File::FLAG_OPEN | File::FLAG_READ:
+    case File::FLAG_OPEN_ALWAYS | File::FLAG_READ:
+    case File::FLAG_CREATE | File::FLAG_READ:
       return "r";
     case File::FLAG_OPEN_ALWAYS | File::FLAG_READ | File::FLAG_WRITE:
       return "rw";
diff --git a/base/android/content_uri_utils_unittest.cc b/base/android/content_uri_utils_unittest.cc
index bfa36281..9104cfc 100644
--- a/base/android/content_uri_utils_unittest.cc
+++ b/base/android/content_uri_utils_unittest.cc
@@ -52,6 +52,8 @@
 TEST(ContentUriUtilsTest, TranslateOpenFlagsToJavaMode) {
   constexpr auto kTranslations = MakeFixedFlatMap<uint32_t, std::string>({
       {File::FLAG_OPEN | File::FLAG_READ, "r"},
+      {File::FLAG_OPEN_ALWAYS | File::FLAG_READ, "r"},
+      {File::FLAG_CREATE | File::FLAG_READ, "r"},
       {File::FLAG_OPEN_ALWAYS | File::FLAG_READ | File::FLAG_WRITE, "rw"},
       {File::FLAG_OPEN_ALWAYS | File::FLAG_APPEND, "wa"},
       {File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE, "rwt"},
diff --git a/base/android/java/src/org/chromium/base/VirtualDocumentPath.java b/base/android/java/src/org/chromium/base/VirtualDocumentPath.java
index b92dad0..e325b9d 100644
--- a/base/android/java/src/org/chromium/base/VirtualDocumentPath.java
+++ b/base/android/java/src/org/chromium/base/VirtualDocumentPath.java
@@ -26,6 +26,27 @@
  */
 @NullMarked
 class VirtualDocumentPath {
+    static class CreateOrOpenResult {
+        public final Uri contentUri;
+        public final boolean created;
+
+        private CreateOrOpenResult(Uri contentUri, boolean created) {
+            this.contentUri = contentUri;
+            this.created = created;
+        }
+
+        @CalledByNative("CreateOrOpenResult")
+        @JniType("std::string")
+        String getContentUriString() {
+            return this.contentUri.toString();
+        }
+
+        @CalledByNative("CreateOrOpenResult")
+        boolean getCreated() {
+            return this.created;
+        }
+    }
+
     private static final String TAG = "VirtualDocumentPath";
 
     private static final String VIRTUAL_PATH_MARKER = "SAF";
@@ -238,33 +259,43 @@
      */
     @CalledByNative
     boolean writeFile(byte[] data) {
-        Uri file = createIfNotExist();
-        if (file == null) return false;
+        CreateOrOpenResult result = createOrOpen();
+        if (result == null) return false;
 
-        try (OutputStream out = mResolver.openOutputStream(file)) {
+        try (OutputStream out = mResolver.openOutputStream(result.contentUri)) {
             if (out == null) return false;
             out.write(data);
             return true;
         } catch (Exception e) {
-            Log.w(TAG, "Failed to write to " + file);
+            Log.w(TAG, "Failed to write to " + result.contentUri);
             return false;
         }
     }
 
-    private @Nullable Uri createIfNotExist() {
+    /**
+     * Creates an empty file if it does not exist and its parent directory exists. It returns the
+     * content uri if the file exists or created.
+     */
+    @CalledByNative
+    @Nullable
+    CreateOrOpenResult createOrOpen() {
         Pair<VirtualDocumentPath, String> pair = splitPath();
         if (pair == null) return null;
         VirtualDocumentPath parent = pair.first;
         String basename = pair.second;
 
         Uri contentUri = resolveToContentUri();
-        if (contentUri != null) return contentUri;
+        if (contentUri != null) {
+            return new CreateOrOpenResult(contentUri, false);
+        }
 
         Uri parentUri = parent.resolveToContentUri();
         if (parentUri == null) return null;
 
         try {
-            return DocumentsContract.createDocument(mResolver, parentUri, "", basename);
+            Uri uri = DocumentsContract.createDocument(mResolver, parentUri, "", basename);
+            if (uri == null) return null;
+            return new CreateOrOpenResult(uri, true);
         } catch (Exception e) {
             Log.w(TAG, "Failed to create file");
             return null;
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index a885fda..ad08aee 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -49,7 +49,8 @@
                          const char* class_name,
                          const char* split_name) {
   DCHECK(IsStringASCII(class_name));
-  ScopedJavaLocalRef<jstring> j_class_name(env, env->NewStringUTF(class_name));
+  auto j_class_name =
+      ScopedJavaLocalRef<jstring>::Adopt(env, env->NewStringUTF(class_name));
   return static_cast<jclass>(env->CallObjectMethod(
       GetSplitClassLoader(env, split_name), g_class_loader_load_class_method_id,
       j_class_name.obj()));
@@ -62,7 +63,7 @@
 void PrepareClassLoaders(JNIEnv* env) {
   if (g_class_loader_load_class_method_id == nullptr) {
     GetClassLoader(env);
-    ScopedJavaLocalRef<jclass> class_loader_clazz = ScopedJavaLocalRef<jclass>(
+    auto class_loader_clazz = ScopedJavaLocalRef<jclass>::Adopt(
         env, env->FindClass("java/lang/ClassLoader"));
     CHECK(!ClearException(env));
     g_class_loader_load_class_method_id =
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index ccd44a79..762c0e6 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -37,7 +37,7 @@
                           reinterpret_cast<const jbyte*>(bytes.data()));
   CheckException(env);
 
-  return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
+  return ScopedJavaLocalRef<jbyteArray>::Adopt(env, byte_array);
 }
 
 ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env,
@@ -68,7 +68,7 @@
                              reinterpret_cast<const jboolean*>(bools.data()));
   CheckException(env);
 
-  return ScopedJavaLocalRef<jbooleanArray>(env, boolean_array);
+  return ScopedJavaLocalRef<jbooleanArray>::Adopt(env, boolean_array);
 }
 
 ScopedJavaLocalRef<jintArray> ToJavaIntArray(JNIEnv* env,
@@ -83,7 +83,7 @@
                          reinterpret_cast<const jint*>(ints.data()));
   CheckException(env);
 
-  return ScopedJavaLocalRef<jintArray>(env, int_array);
+  return ScopedJavaLocalRef<jintArray>::Adopt(env, int_array);
 }
 
 // Returns a new Java long array converted from the given int64_t array.
@@ -101,7 +101,7 @@
                           reinterpret_cast<const jlong*>(longs.data()));
   CheckException(env);
 
-  return ScopedJavaLocalRef<jlongArray>(env, long_array);
+  return ScopedJavaLocalRef<jlongArray>::Adopt(env, long_array);
 }
 
 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
@@ -119,7 +119,7 @@
                            reinterpret_cast<const jfloat*>(floats.data()));
   CheckException(env);
 
-  return ScopedJavaLocalRef<jfloatArray>(env, float_array);
+  return ScopedJavaLocalRef<jfloatArray>::Adopt(env, float_array);
 }
 
 BASE_EXPORT ScopedJavaLocalRef<jdoubleArray> ToJavaDoubleArray(
@@ -137,7 +137,7 @@
                             reinterpret_cast<const jdouble*>(doubles.data()));
   CheckException(env);
 
-  return ScopedJavaLocalRef<jdoubleArray>(env, double_array);
+  return ScopedJavaLocalRef<jdoubleArray>::Adopt(env, double_array);
 }
 
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfObjects(
@@ -151,7 +151,7 @@
   for (size_t i = 0; i < v.size(); ++i) {
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfObjects(
@@ -170,7 +170,7 @@
   for (size_t i = 0; i < v.size(); ++i) {
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToTypedJavaArrayOfObjects(
@@ -184,7 +184,7 @@
   for (size_t i = 0; i < v.size(); ++i) {
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToTypedJavaArrayOfObjects(
@@ -198,7 +198,7 @@
   for (size_t i = 0; i < v.size(); ++i) {
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
@@ -213,7 +213,7 @@
     ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env, v[i]);
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), byte_array.obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
@@ -228,7 +228,7 @@
     ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env, v[i]);
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), byte_array.obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
@@ -242,7 +242,7 @@
     ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), item.obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStringArray(
@@ -261,7 +261,7 @@
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), inner.obj());
   }
 
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStringArray(
@@ -280,7 +280,7 @@
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), inner.obj());
   }
 
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
@@ -294,7 +294,7 @@
     ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
     env->SetObjectArrayElement(joa, checked_cast<jsize>(i), item.obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 void AppendJavaStringArrayToStringVector(JNIEnv* env,
@@ -311,7 +311,7 @@
   out->resize(out->size() + len);
   span<std::u16string> back = span(*out).last(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jstring> str(
+    auto str = ScopedJavaLocalRef<jstring>::Adopt(
         env, static_cast<jstring>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
     ConvertJavaStringToUTF16(env, str.obj(), &back[i]);
@@ -332,7 +332,7 @@
   out->resize(out->size() + len);
   span<std::string> back = span(*out).last(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jstring> str(
+    auto str = ScopedJavaLocalRef<jstring>::Adopt(
         env, static_cast<jstring>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
     ConvertJavaStringToUTF8(env, str.obj(), &back[i]);
@@ -490,7 +490,7 @@
   size_t len = SafeGetArrayLength(env, array);
   out->resize(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jbyteArray> bytes_array(
+    auto bytes_array = ScopedJavaLocalRef<jbyteArray>::Adopt(
         env, static_cast<jbyteArray>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
     size_t bytes_len = SafeGetArrayLength(env, bytes_array);
@@ -517,7 +517,7 @@
   const size_t len = SafeGetArrayLength(env, array);
   out->resize(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jbyteArray> bytes_array(
+    auto bytes_array = ScopedJavaLocalRef<jbyteArray>::Adopt(
         env, static_cast<jbyteArray>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
     JavaByteArrayToByteVector(env, bytes_array, &(*out)[i]);
@@ -532,7 +532,7 @@
   size_t len = SafeGetArrayLength(env, array);
   out->resize(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jobjectArray> strings_array(
+    auto strings_array = ScopedJavaLocalRef<jobjectArray>::Adopt(
         env, static_cast<jobjectArray>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
 
@@ -549,7 +549,7 @@
   size_t len = SafeGetArrayLength(env, array);
   out->resize(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jobjectArray> strings_array(
+    auto strings_array = ScopedJavaLocalRef<jobjectArray>::Adopt(
         env, static_cast<jobjectArray>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
 
@@ -565,7 +565,7 @@
   size_t len = SafeGetArrayLength(env, array);
   out->resize(len);
   for (size_t i = 0; i < len; ++i) {
-    ScopedJavaLocalRef<jintArray> int_array(
+    auto int_array = ScopedJavaLocalRef<jintArray>::Adopt(
         env, static_cast<jintArray>(env->GetObjectArrayElement(
                  array.obj(), checked_cast<jsize>(i))));
     JavaIntArrayToIntVector(env, int_array, &(*out)[i]);
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
index 1bb562b8..4f87cf3 100644
--- a/base/android/jni_array_unittest.cc
+++ b/base/android/jni_array_unittest.cc
@@ -239,7 +239,7 @@
   const auto kBools = std::to_array<bool>({false, true, false});
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jbooleanArray> jbooleans(
+  auto jbooleans = ScopedJavaLocalRef<jbooleanArray>::Adopt(
       env, env->NewBooleanArray(kBools.size()));
   ASSERT_TRUE(jbooleans);
 
@@ -273,7 +273,8 @@
   const auto kInts = std::to_array<int>({0, 1, -1});
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kInts.size()));
+  auto jints =
+      ScopedJavaLocalRef<jintArray>::Adopt(env, env->NewIntArray(kInts.size()));
   ASSERT_TRUE(jints);
 
   for (size_t i = 0; i < kInts.size(); ++i) {
@@ -295,7 +296,8 @@
   const auto kInt64s = std::to_array<int64_t>({0LL, 1LL, -1LL});
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kInt64s.size()));
+  auto jlongs = ScopedJavaLocalRef<jlongArray>::Adopt(
+      env, env->NewLongArray(kInt64s.size()));
   ASSERT_TRUE(jlongs);
 
   for (size_t i = 0; i < kInt64s.size(); ++i) {
@@ -323,7 +325,8 @@
   const auto kInt64s = std::to_array<int64_t>({0LL, 1LL, -1LL});
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jlongArray> jlongs(env, env->NewLongArray(kInt64s.size()));
+  auto jlongs = ScopedJavaLocalRef<jlongArray>::Adopt(
+      env, env->NewLongArray(kInt64s.size()));
   ASSERT_TRUE(jlongs);
 
   for (size_t i = 0; i < kInt64s.size(); ++i) {
@@ -350,8 +353,8 @@
   const auto kFloats = std::to_array<float>({0.0, 0.5, -0.5});
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jfloatArray> jfloats(env,
-                                          env->NewFloatArray(kFloats.size()));
+  auto jfloats = ScopedJavaLocalRef<jfloatArray>::Adopt(
+      env, env->NewFloatArray(kFloats.size()));
   ASSERT_TRUE(jfloats);
 
   for (size_t i = 0; i < kFloats.size(); ++i) {
@@ -378,7 +381,7 @@
   const auto kDoubles = std::to_array<double>(
       {0.0, 0.5, -0.5, std::numeric_limits<double>::min()});
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jdoubleArray> jdoubles(
+  auto jdoubles = ScopedJavaLocalRef<jdoubleArray>::Adopt(
       env, env->NewDoubleArray(kDoubles.size()));
   ASSERT_TRUE(jdoubles);
 
@@ -396,10 +399,11 @@
   JNIEnv* env = AttachCurrentThread();
 
   // Create a byte[][] object.
-  ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+  auto byte_array_clazz =
+      ScopedJavaLocalRef<jclass>::Adopt(env, env->FindClass("[B"));
   ASSERT_TRUE(byte_array_clazz);
 
-  ScopedJavaLocalRef<jobjectArray> array(
+  auto array = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
   ASSERT_TRUE(array);
 
@@ -432,10 +436,11 @@
   JNIEnv* env = AttachCurrentThread();
 
   // Create a byte[][] object.
-  ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+  auto byte_array_clazz =
+      ScopedJavaLocalRef<jclass>::Adopt(env, env->FindClass("[B"));
   ASSERT_TRUE(byte_array_clazz);
 
-  ScopedJavaLocalRef<jobjectArray> array(
+  auto array = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), nullptr));
   ASSERT_TRUE(array);
 
@@ -473,19 +478,19 @@
 
   JNIEnv* env = AttachCurrentThread();
 
-  ScopedJavaLocalRef<jobjectArray> array(
+  auto array = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(kArrays.size(),
                                env->FindClass("[Ljava/lang/String;"), NULL));
   ASSERT_TRUE(array);
 
-  ScopedJavaLocalRef<jclass> string_clazz(env,
-                                          env->FindClass("java/lang/String"));
+  auto string_clazz = ScopedJavaLocalRef<jclass>::Adopt(
+      env, env->FindClass("java/lang/String"));
   ASSERT_TRUE(string_clazz);
 
   for (size_t i = 0; i < kArrays.size(); ++i) {
     const std::vector<std::u16string>& child_data = kArrays[i];
 
-    ScopedJavaLocalRef<jobjectArray> child_array(
+    auto child_array = ScopedJavaLocalRef<jobjectArray>::Adopt(
         env, env->NewObjectArray(child_data.size(), string_clazz.obj(), NULL));
     ASSERT_TRUE(child_array);
 
@@ -509,10 +514,11 @@
   JNIEnv* env = AttachCurrentThread();
 
   // Create an int[][] object.
-  ScopedJavaLocalRef<jclass> int_array_clazz(env, env->FindClass("[I"));
+  auto int_array_clazz =
+      ScopedJavaLocalRef<jclass>::Adopt(env, env->FindClass("[I"));
   ASSERT_TRUE(int_array_clazz);
 
-  ScopedJavaLocalRef<jobjectArray> array(
+  auto array = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(kNumItems, int_array_clazz.obj(), nullptr));
   ASSERT_TRUE(array);
 
@@ -565,17 +571,17 @@
 
   EXPECT_EQ("one",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 0)))));
   EXPECT_EQ("two",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 1)))));
   EXPECT_EQ("three",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 2)))));
 }
@@ -594,17 +600,17 @@
 
   EXPECT_EQ("one",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 0)))));
   EXPECT_EQ("two",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 1)))));
   EXPECT_EQ("three",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 2)))));
 }
@@ -623,17 +629,17 @@
 
   EXPECT_EQ("one",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 0)))));
   EXPECT_EQ("two",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 1)))));
   EXPECT_EQ("three",
             ConvertJavaStringToUTF8(
-                env, ScopedJavaLocalRef<jstring>(
+                env, ScopedJavaLocalRef<jstring>::Adopt(
                          env, static_cast<jstring>(env->GetObjectArrayElement(
                                   j_array.obj(), 2)))));
 }
diff --git a/base/android/jni_bytebuffer_unittest.cc b/base/android/jni_bytebuffer_unittest.cc
index 485685f..46eecd5e 100644
--- a/base/android/jni_bytebuffer_unittest.cc
+++ b/base/android/jni_bytebuffer_unittest.cc
@@ -24,7 +24,7 @@
   uint8_t bytes[] = {0, 1, 2, 3};
   JNIEnv* env = AttachCurrentThread();
 
-  ScopedJavaLocalRef<jobject> jbuffer(
+  auto jbuffer = ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(bytes, sizeof(bytes)));
   ASSERT_TRUE(jbuffer);
 
@@ -46,7 +46,8 @@
       base::android::MethodID::Get<base::android::MethodID::TYPE_INSTANCE>(
           env, cls, "<init>", "()V");
 
-  ScopedJavaLocalRef<jobject> jnonbuffer(env, env->NewObject(cls, init));
+  auto jnonbuffer =
+      ScopedJavaLocalRef<jobject>::Adopt(env, env->NewObject(cls, init));
 
   std::optional<base::span<const uint8_t>> maybe_span =
       MaybeJavaByteBufferToSpan(env, jnonbuffer);
@@ -55,8 +56,8 @@
 
 TEST(JniByteBuffer, ZeroByteConversionSucceeds) {
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> jbuffer(env,
-                                      env->NewDirectByteBuffer(nullptr, 0));
+  auto jbuffer = ScopedJavaLocalRef<jobject>::Adopt(
+      env, env->NewDirectByteBuffer(nullptr, 0));
   ASSERT_TRUE(jbuffer);
 
   base::span<const uint8_t> span = JavaByteBufferToSpan(env, jbuffer);
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
index cea0be7..ede1f29 100644
--- a/base/android/jni_string.cc
+++ b/base/android/jni_string.cc
@@ -94,7 +94,7 @@
   // it gets here, so constructing via UTF16 side-steps this issue.
   // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
   // a significant performance hit by doing it this way).
-  return ScopedJavaLocalRef<jstring>(
+  return ScopedJavaLocalRef<jstring>::Adopt(
       env, ConvertUTF16ToJavaStringImpl(env, UTF8ToUTF16(str)));
 }
 
@@ -155,8 +155,8 @@
   if (str.empty()) {
     return jni_zero::g_empty_string.AsLocalRef(env);
   }
-  return ScopedJavaLocalRef<jstring>(env,
-                                     ConvertUTF16ToJavaStringImpl(env, str));
+  return ScopedJavaLocalRef<jstring>::Adopt(
+      env, ConvertUTF16ToJavaStringImpl(env, str));
 }
 
 }  // namespace android
diff --git a/base/android/meminfo_dump_provider.cc b/base/android/meminfo_dump_provider.cc
index 75bf503c..10899a5 100644
--- a/base/android/meminfo_dump_provider.cc
+++ b/base/android/meminfo_dump_provider.cc
@@ -73,7 +73,8 @@
     return false;
   }
 
-  ScopedJavaLocalRef<jclass> clazz{env, env->GetObjectClass(memory_info.obj())};
+  auto clazz = ScopedJavaLocalRef<jclass>::Adopt(
+      env, env->GetObjectClass(memory_info.obj()));
 
   jfieldID other_private_dirty_id =
       env->GetFieldID(clazz.obj(), "otherPrivateDirty", "I");
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
index 2e5cf81..eb71538 100644
--- a/base/android/scoped_java_ref.h
+++ b/base/android/scoped_java_ref.h
@@ -11,18 +11,16 @@
 namespace android {
 
 using ScopedJavaLocalFrame = jni_zero::ScopedJavaLocalFrame;
-template <typename T>
+template <typename T = jobject>
 using JavaRef = jni_zero::JavaRef<T>;
-template <typename T>
+template <typename T = jobject>
 using JavaObjectArrayReader = jni_zero::JavaObjectArrayReader<T>;
-template <typename T>
+template <typename T = jobject>
 using JavaParamRef = jni_zero::JavaParamRef<T>;
-template <typename T>
+template <typename T = jobject>
 using ScopedJavaLocalRef = jni_zero::ScopedJavaLocalRef<T>;
-template <typename T>
+template <typename T = jobject>
 using ScopedJavaGlobalRef = jni_zero::ScopedJavaGlobalRef<T>;
-template <typename T>
-using JavaObjectArrayReader = jni_zero::JavaObjectArrayReader<T>;
 
 }  // namespace android
 }  // namespace base
diff --git a/base/android/virtual_document_path.cc b/base/android/virtual_document_path.cc
index c46b96a..3615dc9 100644
--- a/base/android/virtual_document_path.cc
+++ b/base/android/virtual_document_path.cc
@@ -65,4 +65,17 @@
   return Java_VirtualDocumentPath_writeFile(env, obj_, bs);
 }
 
+std::optional<std::pair<std::string, bool>> VirtualDocumentPath::CreateOrOpen()
+    const {
+  JNIEnv* env = android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> result =
+      Java_VirtualDocumentPath_createOrOpen(env, obj_);
+  if (result.is_null()) {
+    return std::nullopt;
+  }
+  std::string uri = Java_CreateOrOpenResult_getContentUriString(env, result);
+  bool created = Java_CreateOrOpenResult_getCreated(env, result);
+  return std::make_pair(uri, created);
+}
+
 }  // namespace base::files_internal
diff --git a/base/android/virtual_document_path.h b/base/android/virtual_document_path.h
index ba4a6bf..7947dcb 100644
--- a/base/android/virtual_document_path.h
+++ b/base/android/virtual_document_path.h
@@ -108,6 +108,12 @@
   // has been successfully written, and false otherwise.
   bool WriteFile(span<const uint8_t> data) const;
 
+  // Creates an empty file if it does not exist and its parent directory exists.
+  // If the file exists or created, it returns a pair of two values where the
+  // first value is the content URI, and the second is a bool which is true if
+  // the file has been created and false if the file already existed.
+  std::optional<std::pair<std::string, bool>> CreateOrOpen() const;
+
  private:
   explicit VirtualDocumentPath(const base::android::JavaRef<jobject>& obj);
 
diff --git a/base/byte_count.h b/base/byte_count.h
index e9e366c..8f7f43d7 100644
--- a/base/byte_count.h
+++ b/base/byte_count.h
@@ -73,24 +73,50 @@
 
   // Math operations.
 
-  constexpr ByteCount operator+(ByteCount other) const {
-    return ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) +
-                                  other.bytes_);
+  constexpr ByteCount& operator+=(const ByteCount& other) {
+    *this =
+        ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) + other.bytes_);
+    return *this;
   }
 
-  constexpr ByteCount operator-(ByteCount other) const {
-    return ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) -
-                                  other.bytes_);
+  friend constexpr ByteCount operator+(ByteCount left, const ByteCount& right) {
+    left += right;
+    return left;
+  }
+
+  constexpr ByteCount& operator-=(const ByteCount& other) {
+    *this =
+        ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) - other.bytes_);
+    return *this;
+  }
+
+  friend constexpr ByteCount operator-(ByteCount left, const ByteCount& right) {
+    left -= right;
+    return left;
   }
 
   template <typename T>
-  constexpr ByteCount operator*(T value) const {
-    return ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) * value);
+  constexpr ByteCount& operator*=(const T& value) {
+    *this = ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) * value);
+    return *this;
   }
 
   template <typename T>
-  constexpr ByteCount operator/(T value) const {
-    return ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) / value);
+  friend constexpr ByteCount operator*(ByteCount left, const T& right) {
+    left *= right;
+    return left;
+  }
+
+  template <typename T>
+  constexpr ByteCount& operator/=(const T& value) {
+    *this = ByteCount::FromChecked(CheckedNumeric<int64_t>(bytes_) / value);
+    return *this;
+  }
+
+  template <typename T>
+  friend constexpr ByteCount operator/(ByteCount left, const T& right) {
+    left /= right;
+    return left;
   }
 
   constexpr friend bool operator==(const ByteCount& a,
diff --git a/base/byte_count_unittest.cc b/base/byte_count_unittest.cc
index 821a6c1..6d2ec96c 100644
--- a/base/byte_count_unittest.cc
+++ b/base/byte_count_unittest.cc
@@ -160,6 +160,22 @@
   EXPECT_EQ(21, div.InBytes());
 }
 
+TEST(ByteCount, ArithmeticCompound) {
+  ByteCount bytes(42);
+
+  bytes += ByteCount(10);
+  EXPECT_EQ(52, bytes.InBytes());
+
+  bytes -= ByteCount(10);
+  EXPECT_EQ(42, bytes.InBytes());
+
+  bytes *= 10;
+  EXPECT_EQ(420, bytes.InBytes());
+
+  bytes /= 2;
+  EXPECT_EQ(210, bytes.InBytes());
+}
+
 TEST(ByteCountDeathTest, ArithmeticInvalid) {
   ByteCount max_bytes(std::numeric_limits<int64_t>::max());
 
diff --git a/base/files/file_android.cc b/base/files/file_android.cc
new file mode 100644
index 0000000..a2f892b
--- /dev/null
+++ b/base/files/file_android.cc
@@ -0,0 +1,108 @@
+// 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 "base/files/file_android.h"
+
+#include "base/android/content_uri_utils.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/android/virtual_document_path.h"
+#include "base/check.h"
+#include "base/files/file_util.h"
+
+namespace {
+
+struct OpenContentUriResult {
+  int fd;
+  base::android::ScopedJavaGlobalRef<jobject> java_parcel_file_desciptor;
+};
+
+base::expected<OpenContentUriResult, base::File::Error> OpenContentUriAndGetFd(
+    const base::FilePath& path,
+    uint32_t flags) {
+  CHECK(path.IsContentUri());
+
+  OpenContentUriResult result;
+
+  result.java_parcel_file_desciptor =
+      base::internal::OpenContentUri(path, flags);
+
+  result.fd =
+      base::internal::ContentUriGetFd(result.java_parcel_file_desciptor);
+  if (result.fd < 0) {
+    return base::unexpected(base::File::Error::FILE_ERROR_FAILED);
+  }
+  return result;
+}
+
+}  // namespace
+
+namespace base::files_internal {
+
+OpenAndroidFileResult::OpenAndroidFileResult(
+    base::FilePath content_uri,
+    int fd,
+    base::android::ScopedJavaGlobalRef<jobject> java_parcel_file_descriptor,
+    bool created)
+    : content_uri(content_uri),
+      fd(fd),
+      java_parcel_file_descriptor(java_parcel_file_descriptor),
+      created(created) {}
+
+OpenAndroidFileResult::OpenAndroidFileResult(OpenAndroidFileResult&&) = default;
+OpenAndroidFileResult& OpenAndroidFileResult::operator=(
+    OpenAndroidFileResult&&) = default;
+
+OpenAndroidFileResult::~OpenAndroidFileResult() = default;
+
+base::expected<OpenAndroidFileResult, base::File::Error> OpenAndroidFile(
+    const base::FilePath& path,
+    uint32_t flags) {
+  CHECK(path.IsContentUri() || path.IsVirtualDocumentPath());
+
+  auto cu = ResolveToContentUri(path);
+  if (cu) {
+    if ((flags & File::Flags::FLAG_CREATE)) {
+      return base::unexpected(File::Error::FILE_ERROR_EXISTS);
+    }
+
+    bool created = flags & File::Flags::FLAG_CREATE_ALWAYS;
+    if (auto r = OpenContentUriAndGetFd(*cu, flags); r.has_value()) {
+      return OpenAndroidFileResult(*cu, r->fd, r->java_parcel_file_desciptor,
+                                   created);
+    } else {
+      return base::unexpected(r.error());
+    }
+  }
+
+  // `path` was not resolved to a content URI, meaning it is a virtual document
+  // path that does not exist.
+  CHECK(path.IsVirtualDocumentPath());
+
+  // If the flags don't instruct file creation, return an error.
+  if (!(flags & (File::Flags::FLAG_CREATE | File::Flags::FLAG_CREATE_ALWAYS |
+                 File::Flags::FLAG_OPEN_ALWAYS))) {
+    return base::unexpected(File::Error::FILE_ERROR_NOT_FOUND);
+  }
+
+  std::optional<VirtualDocumentPath> vp =
+      VirtualDocumentPath::Parse(path.value());
+  CHECK(vp);
+
+  std::optional<std::pair<std::string, bool>> create_result =
+      vp->CreateOrOpen();
+  if (!create_result) {
+    return base::unexpected(File::Error::FILE_ERROR_NOT_A_DIRECTORY);
+  }
+  base::FilePath content_uri(create_result->first);
+  bool created = create_result->second;
+
+  if (auto r = OpenContentUriAndGetFd(content_uri, flags); r.has_value()) {
+    return OpenAndroidFileResult(content_uri, r->fd,
+                                 r->java_parcel_file_desciptor, created);
+  } else {
+    return base::unexpected(r.error());
+  }
+}
+
+}  // namespace base::files_internal
diff --git a/base/files/file_android.h b/base/files/file_android.h
new file mode 100644
index 0000000..b8496d3
--- /dev/null
+++ b/base/files/file_android.h
@@ -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.
+
+#ifndef BASE_FILES_FILE_ANDROID_H_
+#define BASE_FILES_FILE_ANDROID_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/types/expected.h"
+
+namespace base::files_internal {
+
+struct OpenAndroidFileResult {
+  OpenAndroidFileResult(
+      base::FilePath content_uri,
+      int fd,
+      base::android::ScopedJavaGlobalRef<jobject> java_parcel_file_descriptor,
+      bool created);
+
+  OpenAndroidFileResult(const OpenAndroidFileResult&) = delete;
+  OpenAndroidFileResult& operator=(const OpenAndroidFileResult&) = delete;
+  OpenAndroidFileResult(OpenAndroidFileResult&&);
+  OpenAndroidFileResult& operator=(OpenAndroidFileResult&&);
+
+  ~OpenAndroidFileResult();
+
+  // The content URI of the file that was opened.
+  base::FilePath content_uri;
+  // The file descriptor. The caller gains ownership of it through the
+  // `java_parcel_file_descriptor` below. When it is closed (in
+  // `File::Close()`), the file descriptor is essentially closed.
+  int fd;
+  // The corresponding Java ParcelFileDescriptor object.
+  base::android::ScopedJavaGlobalRef<jobject> java_parcel_file_descriptor;
+  // Set to true if the file was created or truncated.
+  bool created;
+};
+
+// Open an android file (i.e. content URI or a virtual document path) with given
+// File::Flag.
+base::expected<OpenAndroidFileResult, base::File::Error> OpenAndroidFile(
+    const base::FilePath& path,
+    uint32_t flags);
+
+}  // namespace base::files_internal
+
+#endif  // BASE_FILES_FILE_ANDROID_H_
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index e4166d3..35919ef 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -43,6 +43,7 @@
 #if BUILDFLAG(IS_ANDROID)
 #include "base/android/content_uri_utils.h"
 #include "base/android/virtual_document_path.h"
+#include "base/files/file_android.h"
 #include "base/os_compat_android.h"
 #endif
 
@@ -638,26 +639,19 @@
 
 #if BUILDFLAG(IS_ANDROID)
   if (path.IsContentUri() || path.IsVirtualDocumentPath()) {
-    std::optional<FilePath> content_uri = base::ResolveToContentUri(path);
-    if (!content_uri) {
-      error_details_ = FILE_ERROR_FAILED;
-      return;
-    }
-    java_parcel_file_descriptor_ =
-        internal::OpenContentUri(*content_uri, flags);
-
-    int fd = internal::ContentUriGetFd(java_parcel_file_descriptor_);
-    if (fd < 0) {
-      error_details_ = FILE_ERROR_FAILED;
+    auto result = files_internal::OpenAndroidFile(path, flags);
+    if (!result.has_value()) {
+      error_details_ = result.error();
       return;
     }
 
     // Save path for any call to GetInfo().
-    path_ = *std::move(content_uri);
-    created_ = (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE));
+    path_ = result->content_uri;
+    file_.reset(result->fd);
+    java_parcel_file_descriptor_ = result->java_parcel_file_descriptor;
+    created_ = result->created;
     async_ = (flags & FLAG_ASYNC);
     error_details_ = FILE_OK;
-    file_.reset(fd);
     return;
   }
 #endif
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index b03b1b4..2c2b776 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -25,13 +25,17 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/perfetto/include/perfetto/test/traced_value_test_support.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "base/test/android/content_uri_test_utils.h"
+#endif  // BUILDFLAG(IS_ANDROID)
+
 #if BUILDFLAG(IS_WIN)
 #include <windows.h>
 
 #include "base/environment.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gtest_util.h"
-#endif
+#endif  // BUILDFLAG(IS_WIN)
 
 namespace base {
 
@@ -122,6 +126,85 @@
   EXPECT_FALSE(PathExists(file_path));
 }
 
+#if BUILDFLAG(IS_ANDROID)
+// Same as Create, but exercising FilePaths that are virtual document paths.
+TEST(FileTest, CreateAndroid) {
+  ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+
+  FilePath temp_dir =
+      *test::android::GetVirtualDocumentPathFromCacheDirDirectory(
+          scoped_temp_dir.GetPath());
+
+  FilePath file_path = temp_dir.AppendASCII("create_file_1");
+
+  {
+    // Default-constructed file should be invalid with a default error.
+    File file;
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_EQ(File::FILE_ERROR_FAILED, file.error_details());
+  }
+
+  {
+    // Open a file that doesn't exist.
+    File file(file_path, File::FLAG_OPEN | File::FLAG_READ);
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, file.error_details());
+  }
+
+  {
+    // Open or create a file.
+    File file(file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(File::FILE_OK, file.error_details());
+  }
+
+  {
+    // Open an existing file.
+    File file(file_path, File::FLAG_OPEN | File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(File::FILE_OK, file.error_details());
+
+    // This time verify closing the file.
+    file.Close();
+    EXPECT_FALSE(file.IsValid());
+  }
+
+  {
+    // Open an existing file through Initialize
+    File file;
+    file.Initialize(file_path, File::FLAG_OPEN | File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(File::FILE_OK, file.error_details());
+
+    // This time verify closing the file.
+    file.Close();
+    EXPECT_FALSE(file.IsValid());
+  }
+
+  {
+    // Create a file that exists.
+    File file(file_path, File::FLAG_CREATE | File::FLAG_READ);
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(File::FILE_ERROR_EXISTS, file.error_details());
+  }
+
+  {
+    // Create or overwrite a file.
+    File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(File::FILE_OK, file.error_details());
+  }
+
+  EXPECT_TRUE(PathExists(file_path));
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
 TEST(FileTest, SelfSwap) {
   ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/TripBuilder.java b/base/test/android/javatests/src/org/chromium/base/test/transit/TripBuilder.java
index 03d20c2..a15f7b7 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/TripBuilder.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/TripBuilder.java
@@ -8,6 +8,8 @@
 
 import com.google.errorprone.annotations.CheckReturnValue;
 
+import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.transit.ConditionalState.Phase;
 import org.chromium.base.test.transit.Transition.TransitionOptions;
 import org.chromium.base.test.transit.Transition.Trigger;
@@ -23,6 +25,8 @@
  */
 @SuppressLint("CheckResult")
 public class TripBuilder {
+    private static final String TAG = "Transit";
+
     private final List<Facility<?>> mFacilitiesToEnter = new ArrayList<>();
     private final List<Facility<?>> mFacilitiesToExit = new ArrayList<>();
     private final List<CarryOn> mCarryOnsToPickUp = new ArrayList<>();
@@ -363,4 +367,35 @@
     public <StateT extends ConditionalState> StateT completeAndGet(Class<StateT> stateClass) {
         return complete().get(stateClass);
     }
+
+    /**
+     * Execute the trigger without waiting for any Conditions.
+     *
+     * @throws AssertionError if there are any Conditions to wait for already set.
+     */
+    public void executeTriggerWithoutTransition() {
+        assert mTrigger != null : "Trigger not set";
+        String justRunErrorMessage =
+                "justRun() will not enter or leave any ConditionalStates or check any Conditions";
+        assert mOriginStation == null : justRunErrorMessage;
+        assert mDestinationStation == null : justRunErrorMessage;
+        assert mFacilitiesToExit.isEmpty() : justRunErrorMessage;
+        assert mFacilitiesToEnter.isEmpty() : justRunErrorMessage;
+        assert mCarryOnsToDrop.isEmpty() : justRunErrorMessage;
+        assert mCarryOnsToPickUp.isEmpty() : justRunErrorMessage;
+        assert mConditions.isEmpty() : justRunErrorMessage;
+
+        try {
+            if (mOptions.getRunTriggerOnUiThread()) {
+                Log.i(TAG, "Will run trigger on UI thread");
+                ThreadUtils.runOnUiThread(mTrigger::triggerTransition);
+            } else {
+                Log.i(TAG, "Will run trigger on Instrumentation thread");
+                mTrigger.triggerTransition();
+            }
+            Log.i(TAG, "Finished running trigger");
+        } catch (Throwable e) {
+            throw TravelException.newTravelException(String.format("Trigger threw "), e);
+        }
+    }
 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
index 0eb1ecef..e3a4b319 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
@@ -14,7 +14,6 @@
 
 import org.hamcrest.Matcher;
 
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.transit.ViewConditions.DisplayedCondition;
 import org.chromium.base.test.transit.ViewConditions.NotDisplayedAnymoreCondition;
 import org.chromium.base.test.util.ForgivingClickAction;
@@ -129,73 +128,45 @@
         return mViewSpec.ancestor(viewClass, viewMatcher);
     }
 
-    /** Start a Transition by clicking this View. */
+    /**
+     * Start a Transition by clicking this View.
+     *
+     * <p>Requires the View to be >90% displayed.
+     */
     public TripBuilder clickTo() {
-        return new TripBuilder().withContext(this).withTrigger(getClickTrigger());
+        return performViewActionTo(ViewActions.click());
     }
 
     /** Start a Transition by long pressing this View. */
     public TripBuilder longPressTo() {
-        return new TripBuilder().withContext(this).withTrigger(getLongPressTrigger());
+        return performViewActionTo(ViewActions.longClick());
     }
 
-    /** Start a Transition by clicking this View even if partially occluded. */
+    /**
+     * Start a Transition by clicking this View even if partially occluded.
+     *
+     * <p>Does not require the View to be >90% displayed like {@link #clickTo()}.
+     */
     public TripBuilder clickEvenIfPartiallyOccludedTo() {
-        return new TripBuilder().withContext(this).withTrigger(getForgivingClickTrigger());
+        return performViewActionTo(ForgivingClickAction.forgivingClick());
     }
 
     /** Start a Transition by typing |text| into this View. */
     public TripBuilder typeTextTo(String text) {
-        return new TripBuilder().withContext(this).withTrigger(getTypeTextTrigger(text));
+        return new TripBuilder()
+                .withContext(this)
+                .withRunOnUiThread()
+                .withTrigger(
+                        () ->
+                                KeyUtils.typeTextIntoView(
+                                        InstrumentationRegistry.getInstrumentation(), get(), text));
     }
 
     /** Start a Transition by performing an Espresso ViewAction on this View. */
     public TripBuilder performViewActionTo(ViewAction action) {
-        return new TripBuilder().withContext(this).withTrigger(getPerformTrigger(action));
-    }
-
-    /** Trigger an Espresso action on this View. */
-    public Transition.Trigger getPerformTrigger(ViewAction action) {
-        return () -> Espresso.onView(mViewSpec.getViewMatcher()).perform(action);
-    }
-
-    /**
-     * Trigger an Espresso click on this View.
-     *
-     * <p>Requires it to be >90% displayed.
-     */
-    public Transition.Trigger getClickTrigger() {
-        return getPerformTrigger(ViewActions.click());
-    }
-
-    /**
-     * Trigger an Espresso click on this View.
-     *
-     * <p>Does not require the View to be > 90% displayed like {@link #getClickTrigger()}.
-     *
-     * <p>TODO(crbug.com/411140394): Rename clickTrigger() to strictClickTrigger() and rename this
-     * to clickTrigger().
-     */
-    public Transition.Trigger getForgivingClickTrigger() {
-        return getPerformTrigger(ForgivingClickAction.forgivingClick());
-    }
-
-    /**
-     * Trigger an Espresso long press on this View.
-     *
-     * <p>Requires it to be >90% displayed.
-     */
-    public Transition.Trigger getLongPressTrigger() {
-        return getPerformTrigger(ViewActions.longClick());
-    }
-
-    /** Send keycodes to the View to type |text|. */
-    public Transition.Trigger getTypeTextTrigger(String text) {
-        return () ->
-                ThreadUtils.runOnUiThread(
-                        () ->
-                                KeyUtils.typeTextIntoView(
-                                        InstrumentationRegistry.getInstrumentation(), get(), text));
+        return new TripBuilder()
+                .withContext(this)
+                .withTrigger(() -> Espresso.onView(mViewSpec.getViewMatcher()).perform(action));
     }
 
     /** Trigger an Espresso ViewAssertion on this View. */
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index 475ebf31c..7727ed7 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -835,7 +835,8 @@
   ::GetThreadTimes(thread_handle.platform_handle(), &creation_time, &exit_time,
                    &kernel_time, &user_time);
 
-  const int64_t us = FileTimeToMicroseconds(user_time);
+  const int64_t us =
+      FileTimeToMicroseconds(user_time) + FileTimeToMicroseconds(kernel_time);
 #else
   // Get the number of TSC ticks used by the current thread.
   ULONG64 thread_cycle_time = 0;
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 92a6967..f990f09 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -222,12 +222,32 @@
 
     # The orderfile is trained on PGO builds (for arm64) and AFDO builds (for
     # arm32), so apply them only in these cases.
-    if (defined(default_chrome_orderfile)) {
-      if (((current_cpu == "arm64" || current_cpu == "x64") &&
-           chrome_pgo_phase == 2) ||
-          ((current_cpu == "arm" || current_cpu == "x86") &&
-           clang_use_default_sample_profile)) {
+    if (((current_cpu == "arm64" || current_cpu == "x64") &&
+         chrome_pgo_phase == 2) ||
+        ((current_cpu == "arm" || current_cpu == "x86") &&
+         clang_use_default_sample_profile)) {
+      if (defined(default_chrome_orderfile)) {
         chrome_orderfile_path = default_chrome_orderfile
+      } else if (enable_chrome_android_internal) {
+        # We generate separate orderfiles for 32-bit and 64-bit architectures
+        # to improve performance and reduce memory usage.
+        # - WebView and Chrome ARM64, see https://crbug.com/41490637.
+        # - WebView and Chrome x86, see https://crbug.com/967343.
+        # *IMPORTANT*: The x86 and x64 architectures are used to test orderfile
+        # logic more easily on an emulator, so the decision to use the arm64
+        # orderfile for x64 (instead of arm32) is somewhat arbitrary. We just
+        # needed to use some real orderfile.
+        if (is_desktop_android && current_cpu == "x64") {
+          # For Android Desktop x64, orderfile is disabled, see
+          # https://crbug.com/422005929.
+          chrome_orderfile_path = ""
+        } else if (current_cpu == "arm64" || current_cpu == "x64") {
+          chrome_orderfile_path =
+              "//chrome/android/orderfiles/arm64/orderfile.arm64.out"
+        } else if (current_cpu == "arm" || current_cpu == "x86") {
+          chrome_orderfile_path =
+              "//chrome/android/orderfiles/arm/orderfile.arm.out"
+        }
       }
     }
   }
@@ -370,6 +390,20 @@
     cflags += [ "-fno-ident" ]
   }
 
+  # We cannot rely on errno being set after math functions,
+  # especially since glibc does not set it. Thus, use -fno-math-errno
+  # so that the compiler knows it can inline math functions.
+  # Note that this is different from -ffast-math (even though -ffast-math
+  # implies -fno-math-errno), which also allows a number of unsafe
+  # optimizations. This flag must be consistently set for both module
+  # precompilation and normal source compilation, which means it's enabled for
+  # some targets even in debug builds.
+  if (is_win && is_clang) {
+    cflags += [ "/clang:-fno-math-errno" ]
+  } else if (!is_win) {
+    cflags += [ "-fno-math-errno" ]
+  }
+
   # In general, Windows is totally different, but all the other builds share
   # some common compiler and linker configuration.
   if (!is_win) {
@@ -2611,11 +2645,6 @@
   if (is_official_build) {
     common_optimize_on_ldflags += [ "/OPT:REF" ]  # Remove unreferenced data.
   }
-
-  if (is_clang) {
-    # See below.
-    common_optimize_on_cflags += [ "/clang:-fno-math-errno" ]
-  }
 } else {
   common_optimize_on_cflags = []
   common_optimize_on_ldflags = []
@@ -2667,18 +2696,6 @@
 
     common_optimize_on_ldflags += [ "-Wl,--gc-sections" ]
   }
-
-  # Do not add -fno-math-errno when `is_debug` is true and `use_clang_modules` is true,
-  # as this flag is incompatible with debug builds using modules.
-  if (!is_debug || !use_clang_modules) {
-    # We cannot rely on errno being set after math functions,
-    # especially since glibc does not set it. Thus, use -fno-math-errno
-    # so that the compiler knows it can inline math functions.
-    # Note that this is different from -ffast-math (even though -ffast-math
-    # implies -fno-math-errno), which also allows a number of unsafe
-    # optimizations.
-    common_optimize_on_cflags += [ "-fno-math-errno" ]
-  }
 }
 
 config("default_stack_frames") {
diff --git a/build/rust/cargo_crate.gni b/build/rust/cargo_crate.gni
index 6e0ea2b..c9d7d8f 100644
--- a/build/rust/cargo_crate.gni
+++ b/build/rust/cargo_crate.gni
@@ -91,6 +91,7 @@
 #  cargo_pkg_version
 #  cargo_pkg_name
 #  cargo_pkg_description
+#  cargo_pkg_repository
 #    Strings as found within 'version' and similar fields within Cargo.toml.
 #    Converted to environment variables passed to rustc, in case the crate
 #    uses clap `crate_version!` or `crate_authors!` macros (fairly common in
@@ -154,6 +155,9 @@
   if (defined(invoker.cargo_pkg_description)) {
     _rustenv += [ "CARGO_PKG_DESCRIPTION=${invoker.cargo_pkg_description}" ]
   }
+  if (defined(invoker.cargo_pkg_repository)) {
+    _rustenv += [ "CARGO_PKG_REPOSITORY=${invoker.cargo_pkg_repository}" ]
+  }
 
   # Try to determine the CARGO_MANIFEST_DIR, preferring the directory
   # with build.rs and otherwise assuming that the target contains a
diff --git a/build/rust/std/BUILD.gn.hbs b/build/rust/std/BUILD.gn.hbs
index 47c1f29..ee0a8e3 100644
--- a/build/rust/std/BUILD.gn.hbs
+++ b/build/rust/std/BUILD.gn.hbs
@@ -41,6 +41,11 @@
       cargo_pkg_description = "{{gn_escape this}}"
     {{/with}}
   {{/if}}
+  {{#if cargo_pkg_repository}}
+    {{#with cargo_pkg_repository}}
+      cargo_pkg_repository = "{{this}}"
+    {{/with}}
+  {{/if}}
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
diff --git a/build/rust/std/rules/BUILD.gn b/build/rust/std/rules/BUILD.gn
index 1f06e4f..b51bd50 100644
--- a/build/rust/std/rules/BUILD.gn
+++ b/build/rust/std/rules/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_name = "addr2line"
   cargo_pkg_description =
       "A cross-platform symbolication library written in Rust, using `gimli`"
+  cargo_pkg_repository = "https://github.com/gimli-rs/addr2line"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -91,6 +92,7 @@
   cargo_pkg_name = "adler2"
   cargo_pkg_description =
       "A simple clean-room implementation of the Adler-32 checksum"
+  cargo_pkg_repository = "https://github.com/oyvindln/adler2"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -212,6 +214,7 @@
   cargo_pkg_version = "0.0.0"
   cargo_pkg_name = "alloc"
   cargo_pkg_description = "The Rust core allocation and collections library"
+  cargo_pkg_repository = "https://github.com/rust-lang/rust.git"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -254,6 +257,7 @@
   cargo_pkg_authors = "Alex Crichton <alex@alexcrichton.com>"
   cargo_pkg_name = "cfg-if"
   cargo_pkg_description = "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted."
+  cargo_pkg_repository = "https://github.com/rust-lang/cfg-if"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -493,6 +497,7 @@
   cargo_pkg_authors = "Jorge Aparicio <japaricious@gmail.com>"
   cargo_pkg_name = "compiler_builtins"
   cargo_pkg_description = "Compiler intrinsics used by the Rust compiler."
+  cargo_pkg_repository = "https://github.com/rust-lang/compiler-builtins"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1040,6 +1045,7 @@
   cargo_pkg_version = "0.0.0"
   cargo_pkg_name = "core"
   cargo_pkg_description = "The Rust Core Library"
+  cargo_pkg_repository = "https://github.com/rust-lang/rust.git"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1084,6 +1090,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "getopts"
   cargo_pkg_description = "getopts-like option parsing"
+  cargo_pkg_repository = "https://github.com/rust-lang/getopts"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1183,6 +1190,7 @@
   cargo_pkg_name = "gimli"
   cargo_pkg_description =
       "A library for reading and writing the DWARF debugging format."
+  cargo_pkg_repository = "https://github.com/gimli-rs/gimli"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1266,6 +1274,7 @@
   cargo_pkg_authors = "Amanieu d'Antras <amanieu@gmail.com>"
   cargo_pkg_name = "hashbrown"
   cargo_pkg_description = "A Rust port of Google's SwissTable hash map"
+  cargo_pkg_repository = "https://github.com/rust-lang/hashbrown"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1501,6 +1510,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "libc"
   cargo_pkg_description = "Raw FFI bindings to platform libraries like libc."
+  cargo_pkg_repository = "https://github.com/rust-lang/libc"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1596,6 +1606,7 @@
   cargo_pkg_authors = "Andrew Gallant <jamslam@gmail.com>, bluss"
   cargo_pkg_name = "memchr"
   cargo_pkg_description = "Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for 1, 2 or 3 byte search and single substring search."
+  cargo_pkg_repository = "https://github.com/BurntSushi/memchr"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1662,6 +1673,8 @@
   cargo_pkg_authors = "Frommi <daniil.liferenko@gmail.com>, oyvindln <oyvindln@users.noreply.github.com>, Rich Geldreich richgel99@gmail.com"
   cargo_pkg_name = "miniz_oxide"
   cargo_pkg_description = "DEFLATE compression and decompression library rewritten in Rust based on miniz"
+  cargo_pkg_repository =
+      "https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1800,6 +1813,7 @@
   cargo_pkg_name = "object"
   cargo_pkg_description =
       "A unified interface for reading and writing object file formats."
+  cargo_pkg_repository = "https://github.com/gimli-rs/object"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1869,6 +1883,7 @@
   cargo_pkg_version = "0.0.0"
   cargo_pkg_name = "panic_abort"
   cargo_pkg_description = "Implementation of Rust panics via process aborts"
+  cargo_pkg_repository = "https://github.com/rust-lang/rust.git"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -1924,6 +1939,7 @@
   cargo_pkg_version = "0.0.0"
   cargo_pkg_name = "panic_unwind"
   cargo_pkg_description = "Implementation of Rust panics via stack unwinding"
+  cargo_pkg_repository = "https://github.com/rust-lang/rust.git"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -2074,6 +2090,7 @@
   cargo_pkg_authors = "Alex Crichton <alex@alexcrichton.com>"
   cargo_pkg_name = "rustc-demangle"
   cargo_pkg_description = "Rust compiler symbol demangling."
+  cargo_pkg_repository = "https://github.com/rust-lang/rustc-demangle"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -2124,6 +2141,7 @@
   cargo_pkg_version = "0.0.2"
   cargo_pkg_name = "rustc-literal-escaper"
   cargo_pkg_description = "Provides code to unescape string literals"
+  cargo_pkg_repository = "https://github.com/rust-lang/literal-escaper"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -2952,6 +2970,7 @@
   cargo_pkg_version = "0.0.0"
   cargo_pkg_name = "std"
   cargo_pkg_description = "The Rust Standard Library"
+  cargo_pkg_repository = "https://github.com/rust-lang/rust.git"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -3069,6 +3088,7 @@
   cargo_pkg_name = "std_detect"
   cargo_pkg_description =
       "`std::detect` - Rust's standard library run-time CPU feature detection."
+  cargo_pkg_repository = "https://github.com/rust-lang/stdarch"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -3255,6 +3275,7 @@
       "kwantam <kwantam@gmail.com>, Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "unicode-width"
   cargo_pkg_description = "Determine displayed width of `char` and `str` types according to Unicode Standard Annex #11 rules."
+  cargo_pkg_repository = "https://github.com/unicode-rs/unicode-width"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -3311,6 +3332,7 @@
   edition = "2024"
   cargo_pkg_version = "0.0.0"
   cargo_pkg_name = "unwind"
+  cargo_pkg_repository = "https://github.com/rust-lang/rust.git"
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
diff --git a/buildtools/third_party/libc++/BUILD.gn b/buildtools/third_party/libc++/BUILD.gn
index f4e46e2..358ecb55 100644
--- a/buildtools/third_party/libc++/BUILD.gn
+++ b/buildtools/third_party/libc++/BUILD.gn
@@ -3,12 +3,11 @@
 # found in the LICENSE file.
 
 import("//build/config/c++/c++.gni")
-import("//build/config/c++/modules.gni")
-import("//build/config/clang/clang.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/toolchain/toolchain.gni")
 import("//buildtools/third_party/libc++/libcxx_headers.gni")
+import("//buildtools/third_party/libc++/modules.gni")
 
 if (is_mac) {
   import("//build/config/mac/mac_sdk.gni")
@@ -59,65 +58,7 @@
   ]
 }
 
-configs_to_add = [
-  ":config",
-  "//build/config/compiler:no_chromium_code",
-]
-
-configs_to_remove = [
-  "//build/config/compiler:chromium_code",
-  "//build/config/coverage:default_coverage",
-]
-
 if (use_clang_modules) {
-  template("modulemap") {
-    source_set(target_name) {
-      forward_variables_from(invoker,
-                             [
-                               "deps",
-                               "public_configs",
-                               "public_deps",
-                             ])
-      use_libcxx_modules = false
-      sources = [ invoker.modulemap ]
-
-      # By always including all module maps, we can get it to error out if
-      # we attempt to include something not in your dependencies.
-      # Otherwise, it would silently add it to your own AST.
-      cflags = module_map_flags
-      configs -= configs_to_remove
-      configs += configs_to_add
-    }
-  }
-
-  # When I change sysroot_features from an alias to a group, it omits
-  # -fmodule-file for the aliased target from the command-line.
-  # This seems like it might be a bug in GN, but I'm not waiting for a fix
-  # before submitting this.
-  template("alias") {
-    source_set(target_name) {
-      public_deps = invoker.actual
-      use_libcxx_modules = false
-    }
-  }
-
-  if (defined(sysroot_modulemap)) {
-    template("sysroot_modules") {
-      modulemap(target_name) {
-        forward_variables_from(invoker,
-                               [
-                                 "public_configs",
-                                 "public_deps",
-                               ])
-        modulemap = sysroot_modulemap
-        deps = [
-          ":copy_custom_headers",
-          ":copy_libcxx_headers",
-        ]
-      }
-    }
-  }
-
   if (is_linux || is_chromeos) {
     textual_module("sysroot_ctype") {
     }
@@ -135,7 +76,7 @@
         ":sysroot_features",
       ]
     }
-    sysroot_modules("sysroot_limits") {
+    sysroot_module("sysroot_limits") {
     }
 
     alias("sysroot_locale") {
@@ -173,7 +114,7 @@
     textual_module("sysroot_wctype") {
     }
 
-    sysroot_modules("sysroot") {
+    sysroot_module("sysroot") {
       public_deps = [
         ":_Builtin_limits",
         ":_Builtin_stdarg",
@@ -196,7 +137,7 @@
       public_deps = [ ":sysroot" ]
     }
 
-    sysroot_modules("sysroot_features") {
+    sysroot_module("sysroot_features") {
     }
 
     textual_module("sysroot_fenv") {
@@ -272,7 +213,7 @@
       defines = [ "_LIBCPP_WCHAR_H_HAS_CONST_OVERLOADS" ]
     }
 
-    sysroot_modules("sysroot") {
+    sysroot_module("sysroot") {
       public_deps = [
         ":_Builtin_limits",
         ":_Builtin_stdarg",
@@ -289,14 +230,7 @@
       ]
     }
   } else if (is_mac) {
-    template("DarwinBasic_modules") {
-      modulemap(target_name) {
-        forward_variables_from(invoker, [ "public_deps" ])
-        modulemap = "$mac_sdk_path/usr/include/DarwinBasic.modulemap"
-      }
-    }
-
-    DarwinBasic_modules("MachO") {
+    DarwinBasic_module("MachO") {
       public_deps = [
         ":_Builtin_stdbool",
         ":_Builtin_stdint",
@@ -309,29 +243,29 @@
       ]
     }
 
-    DarwinBasic_modules("_strings") {
+    DarwinBasic_module("_strings") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinBasic_modules("alloca") {
+    DarwinBasic_module("alloca") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinBasic_modules("gethostuuid") {
+    DarwinBasic_module("gethostuuid") {
       public_deps = [
         ":_time",
         ":uuid",
       ]
     }
 
-    DarwinBasic_modules("nl_types") {
+    DarwinBasic_module("nl_types") {
       public_deps = [
         ":DarwinFoundation",
         ":sys_types",
       ]
     }
 
-    DarwinBasic_modules("pthread") {
+    DarwinBasic_module("pthread") {
       public_deps = [
         ":DarwinFoundation",
         ":_signal",
@@ -340,11 +274,11 @@
       ]
     }
 
-    DarwinBasic_modules("runetype") {
+    DarwinBasic_module("runetype") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinBasic_modules("sys_select") {
+    DarwinBasic_module("sys_select") {
       public_deps = [
         ":DarwinFoundation",
         ":_signal",
@@ -354,7 +288,7 @@
       ]
     }
 
-    DarwinBasic_modules("sys_types") {
+    DarwinBasic_module("sys_types") {
       public_deps = [
         ":DarwinFoundation",
         ":_errno",
@@ -364,7 +298,7 @@
       ]
     }
 
-    DarwinBasic_modules("sys_wait") {
+    DarwinBasic_module("sys_wait") {
       public_deps = [
         ":DarwinFoundation",
         ":_signal",
@@ -373,7 +307,7 @@
       ]
     }
 
-    DarwinBasic_modules("sys_resource") {
+    DarwinBasic_module("sys_resource") {
       public_deps = [
         ":DarwinFoundation",
         ":_Builtin_stdint",
@@ -382,7 +316,7 @@
       ]
     }
 
-    DarwinBasic_modules("unistd") {
+    DarwinBasic_module("unistd") {
       public_deps = [
         ":DarwinFoundation",
         ":_limits",
@@ -393,104 +327,93 @@
       ]
     }
 
-    DarwinBasic_modules("xlocale") {
+    DarwinBasic_module("xlocale") {
       public_deps = [
         ":DarwinFoundation",
         ":_locale",
       ]
     }
 
-    template("DarwinFoundation_modules") {
-      modulemap(target_name) {
-        forward_variables_from(invoker, [ "public_deps" ])
-        modulemap = "$mac_sdk_path/usr/include/DarwinFoundation.modulemap"
-      }
-    }
-
-    DarwinFoundation_modules("DarwinFoundation") {
+    DarwinFoundation_module("DarwinFoundation") {
       public_deps = [
         ":_Builtin_stdarg",
         ":_Builtin_stddef",
       ]
     }
 
-    DarwinFoundation_modules("_sys_select") {
+    DarwinFoundation_module("_sys_select") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinFoundation_modules("_useconds_t") {
+    DarwinFoundation_module("_useconds_t") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinFoundation_modules("mach") {
+    DarwinFoundation_module("mach") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinFoundation_modules("netinet_in") {
+    DarwinFoundation_module("netinet_in") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinFoundation_modules("sys_time") {
+    DarwinFoundation_module("sys_time") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    DarwinFoundation_modules("uuid") {
+    DarwinFoundation_module("uuid") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    template("c_standard_library_modules") {
-      modulemap(target_name) {
-        forward_variables_from(invoker, [ "public_deps" ])
-        modulemap = "$mac_sdk_path/usr/include/c_standard_library.modulemap"
-      }
+    c_standard_library_module("__wctype") {
+      public_deps = [
+        ":_ctype",
+        ":std_ctype_h",
+      ]
     }
 
-    c_standard_library_modules("__wctype") {
-      public_deps = [ ":_ctype" ]
-    }
-
-    c_standard_library_modules("_assert") {
+    c_standard_library_module("_assert") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_ctype") {
+    c_standard_library_module("_ctype") {
       public_deps = [
         ":DarwinFoundation",
         ":runetype",
       ]
     }
 
-    c_standard_library_modules("_errno") {
+    c_standard_library_module("_errno") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_fenv") {
+    c_standard_library_module("_fenv") {
     }
 
-    c_standard_library_modules("_inttypes") {
+    c_standard_library_module("_inttypes") {
       public_deps = [
         ":_Builtin_stdint",
         ":_stdint",
       ]
     }
 
-    c_standard_library_modules("_limits") {
+    c_standard_library_module("_limits") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_locale") {
+    c_standard_library_module("_locale") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_math") {
+    c_standard_library_module("_math") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_setjmp") {
+    c_standard_library_module("_setjmp") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_signal") {
+    c_standard_library_module("_signal") {
       public_deps = [
         ":DarwinFoundation",
         ":mach",
@@ -498,18 +421,18 @@
       ]
     }
 
-    c_standard_library_modules("_stdint") {
+    c_standard_library_module("_stdint") {
       public_deps = [ ":DarwinFoundation" ]
     }
 
-    c_standard_library_modules("_stdio") {
+    c_standard_library_module("_stdio") {
       public_deps = [
         ":DarwinFoundation",
         ":sys_types",
       ]
     }
 
-    c_standard_library_modules("_stdlib") {
+    c_standard_library_module("_stdlib") {
       public_deps = [
         ":_signal",
         ":_stdint",
@@ -519,7 +442,7 @@
       ]
     }
 
-    c_standard_library_modules("_string") {
+    c_standard_library_module("_string") {
       public_deps = [
         ":DarwinFoundation",
         ":_strings",
@@ -527,14 +450,14 @@
       ]
     }
 
-    c_standard_library_modules("_time") {
+    c_standard_library_module("_time") {
       public_deps = [
         ":DarwinFoundation",
         ":sys_types",
       ]
     }
 
-    c_standard_library_modules("_wchar") {
+    c_standard_library_module("_wchar") {
       public_deps = [
         ":__wctype",
         ":_stdio",
@@ -542,7 +465,7 @@
       ]
     }
 
-    c_standard_library_modules("_wctype") {
+    c_standard_library_module("_wctype") {
       public_deps = [ ":__wctype" ]
     }
 
@@ -634,18 +557,10 @@
     }
   }
 
-  template("builtin_modules") {
-    # This is a template to build clang builtin's module file.
-    modulemap(target_name) {
-      forward_variables_from(invoker, [ "public_deps" ])
-      modulemap = "${clang_base_path}/lib/clang/${clang_version}/include/module.modulemap"
-    }
+  builtin_module("_Builtin_float") {
   }
 
-  builtin_modules("_Builtin_float") {
-  }
-
-  builtin_modules("_Builtin_intrinsics") {
+  builtin_module("_Builtin_intrinsics") {
     public_deps = [
       ":std_core",
       ":sysroot_stdlib",
@@ -656,24 +571,24 @@
     }
   }
 
-  builtin_modules("_Builtin_inttypes") {
+  builtin_module("_Builtin_inttypes") {
     public_deps = [ ":sysroot_inttypes" ]
   }
 
-  builtin_modules("_Builtin_limits") {
+  builtin_module("_Builtin_limits") {
     public_deps = [
       ":std_float_h",
       ":sysroot_limits",
     ]
   }
 
-  builtin_modules("_Builtin_stdalign") {
+  builtin_module("_Builtin_stdalign") {
   }
 
-  builtin_modules("_Builtin_stdarg") {
+  builtin_module("_Builtin_stdarg") {
   }
 
-  builtin_modules("_Builtin_stdatomic") {
+  builtin_module("_Builtin_stdatomic") {
     public_deps = [
       ":_Builtin_stddef",
       ":_Builtin_stdint",
@@ -681,21 +596,21 @@
     ]
   }
 
-  builtin_modules("_Builtin_stdbool") {
+  builtin_module("_Builtin_stdbool") {
   }
 
-  builtin_modules("_Builtin_stddef") {
+  builtin_module("_Builtin_stddef") {
   }
 
-  builtin_modules("_Builtin_stdint") {
+  builtin_module("_Builtin_stdint") {
     public_deps = [ ":sysroot_stdint" ]
   }
 
-  builtin_modules("_Builtin_unwind") {
+  builtin_module("_Builtin_unwind") {
     public_deps = [ ":_Builtin_stdint" ]
   }
 
-  builtin_modules("ptrauth") {
+  builtin_module("ptrauth") {
   }
 
   alias("all_builtins") {
@@ -732,20 +647,7 @@
     ]
   }
 
-  template("libcxx_modules") {
-    # This is a template to build libc++'s module file.
-    modulemap(target_name) {
-      forward_variables_from(invoker, [ "public_deps" ])
-      modulemap =
-          "${root_gen_dir}/third_party/libc++/src/include/module.modulemap"
-      deps = [
-        ":copy_custom_headers",
-        ":copy_libcxx_headers",
-      ]
-    }
-  }
-
-  libcxx_modules("std") {
+  libcxx_module("std") {
     public_deps = [
       ":_Builtin_limits",
       ":_Builtin_stdalign",
@@ -786,7 +688,7 @@
     }
   }
 
-  libcxx_modules("std_core") {
+  libcxx_module("std_core") {
     public_deps = [
       ":_Builtin_stddef",
       ":_Builtin_stdint",
@@ -794,42 +696,42 @@
     ]
   }
 
-  libcxx_modules("std_ctype_h") {
+  libcxx_module("std_ctype_h") {
     public_deps = [
       ":std_config",
       ":sysroot_ctype",
     ]
   }
 
-  libcxx_modules("std_errno_h") {
+  libcxx_module("std_errno_h") {
     public_deps = [
       ":std_config",
       ":sysroot_errno",
     ]
   }
 
-  libcxx_modules("std_fenv_h") {
+  libcxx_module("std_fenv_h") {
     public_deps = [
       ":std_config",
       ":sysroot_fenv",
     ]
   }
 
-  libcxx_modules("std_float_h") {
+  libcxx_module("std_float_h") {
     public_deps = [
       ":_Builtin_float",
       ":std_config",
     ]
   }
 
-  libcxx_modules("std_inttypes_h") {
+  libcxx_module("std_inttypes_h") {
     public_deps = [
       ":_Builtin_inttypes",
       ":std_config",
     ]
   }
 
-  libcxx_modules("std_math_h") {
+  libcxx_module("std_math_h") {
     public_deps = [
       ":std_core",
       ":sysroot_math",
@@ -837,14 +739,14 @@
     ]
   }
 
-  libcxx_modules("std_private_mbstate_t") {
+  libcxx_module("std_private_mbstate_t") {
     public_deps = [
       ":std_config",
       ":sysroot_wchar",
     ]
   }
 
-  libcxx_modules("std_stdatomic_h") {
+  libcxx_module("std_stdatomic_h") {
     public_deps = [
       ":_Builtin_stdatomic",
       ":std_config",
@@ -852,21 +754,21 @@
     ]
   }
 
-  libcxx_modules("std_string_h") {
+  libcxx_module("std_string_h") {
     public_deps = [
       ":std_config",
       ":sysroot_string",
     ]
   }
 
-  libcxx_modules("std_uchar_h") {
+  libcxx_module("std_uchar_h") {
     public_deps = [
       ":std_private_mbstate_t",
       ":sysroot_uchar",
     ]
   }
 
-  libcxx_modules("std_wctype_h") {
+  libcxx_module("std_wctype_h") {
     public_deps = [
       ":std_config",
       ":sysroot_wctype",
@@ -908,7 +810,7 @@
   # need to explicitly depend on libc++.
   visibility = [
     "//build/config:common_deps",
-    "//third_party/catapult/devil:devil",
+    "//third_party/catapult/devil",
   ]
   if (is_linux) {
     # This target packages libc++.so, so must have an explicit dependency on
diff --git a/buildtools/third_party/libc++/modules.gni b/buildtools/third_party/libc++/modules.gni
new file mode 100644
index 0000000..91bfcd66
--- /dev/null
+++ b/buildtools/third_party/libc++/modules.gni
@@ -0,0 +1,102 @@
+# 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/c++/modules.gni")
+import("//build/config/clang/clang.gni")
+
+configs_to_add = [
+  "//buildtools/third_party/libc++:config",
+  "//build/config/compiler:no_chromium_code",
+]
+
+configs_to_remove = [
+  "//build/config/compiler:chromium_code",
+  "//build/config/coverage:default_coverage",
+]
+
+if (use_clang_modules) {
+  template("modulemap") {
+    source_set(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "deps",
+                               "public_configs",
+                               "public_deps",
+                             ])
+      use_libcxx_modules = false
+      sources = [ invoker.modulemap ]
+
+      # By always including all module maps, we can get it to error out if
+      # we attempt to include something not in your dependencies.
+      # Otherwise, it would silently add it to your own AST.
+      cflags = module_map_flags
+      configs -= configs_to_remove
+      configs += configs_to_add
+    }
+  }
+
+  # When I change sysroot_features from an alias to a group, it omits
+  # -fmodule-file for the aliased target from the command-line.
+  # This seems like it might be a bug in GN, but I'm not waiting for a fix
+  # before submitting this.
+  template("alias") {
+    source_set(target_name) {
+      public_deps = invoker.actual
+      use_libcxx_modules = false
+    }
+  }
+
+  template("builtin_module") {
+    # This is a template to build clang builtin's module file.
+    modulemap(target_name) {
+      forward_variables_from(invoker, "*")
+      modulemap = "${clang_base_path}/lib/clang/${clang_version}/include/module.modulemap"
+    }
+  }
+
+  template("libcxx_module") {
+    # This is a template to build libc++'s module file.
+    modulemap(target_name) {
+      forward_variables_from(invoker, "*")
+      modulemap =
+          "${root_gen_dir}/third_party/libc++/src/include/module.modulemap"
+      deps = [
+        "//buildtools/third_party/libc++:copy_custom_headers",
+        "//buildtools/third_party/libc++:copy_libcxx_headers",
+      ]
+    }
+  }
+
+  if (is_mac || is_ios) {
+    template("DarwinBasic_module") {
+      modulemap(target_name) {
+        forward_variables_from(invoker, "*")
+        modulemap = "$mac_sdk_path/usr/include/DarwinBasic.modulemap"
+      }
+    }
+    template("DarwinFoundation_module") {
+      modulemap(target_name) {
+        forward_variables_from(invoker, "*")
+        modulemap = "$mac_sdk_path/usr/include/DarwinFoundation.modulemap"
+      }
+    }
+    template("c_standard_library_module") {
+      modulemap(target_name) {
+        forward_variables_from(invoker, "*")
+        modulemap = "$mac_sdk_path/usr/include/c_standard_library.modulemap"
+      }
+    }
+  } else {
+    template("sysroot_module") {
+      modulemap(target_name) {
+        forward_variables_from(invoker, "*")
+        modulemap = sysroot_modulemap
+        deps = [
+          ":copy_custom_headers",
+          ":copy_libcxx_headers",
+        ]
+      }
+    }
+  }
+}
diff --git a/cc/base/histograms.cc b/cc/base/histograms.cc
index e926632..305c0ff 100644
--- a/cc/base/histograms.cc
+++ b/cc/base/histograms.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 "cc/base/histograms.h"
 
 #include <stdint.h>
@@ -16,6 +11,7 @@
 #include <cstring>
 #include <limits>
 
+#include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
@@ -39,7 +35,7 @@
 
   // If a different name is set, return nullptr from now on and log a warning.
   const char* old_client_name = g_client_name;
-  if (old_client_name && strcmp(old_client_name, client_name)) {
+  if (old_client_name && UNSAFE_TODO(strcmp(old_client_name, client_name))) {
     g_client_name = nullptr;
     g_multiple_client_names_set = true;
     LOG(WARNING) << "Started multiple compositor clients (" << old_client_name
diff --git a/cc/base/list_container_helper.cc b/cc/base/list_container_helper.cc
index 5ee76e9..7b33e83 100644
--- a/cc/base/list_container_helper.cc
+++ b/cc/base/list_container_helper.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 "cc/base/list_container_helper.h"
 
 #include <stddef.h>
@@ -17,6 +12,7 @@
 #include <vector>
 
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/memory/aligned_memory.h"
 #include "base/memory/raw_ptr_exclusion.h"
 
@@ -63,7 +59,7 @@
       // allocation, it doesn't handle desctrution before deallocation.
       DCHECK_LE(position, LastElement());
       DCHECK_GE(position, Begin());
-      char* start = position + step;
+      char* start = UNSAFE_TODO(position + step);
       std::copy(start, End(), position);
 
       --size;
@@ -72,7 +68,7 @@
     }
 
     void InsertBefore(size_t alignment, char** position, size_t count) {
-      DCHECK_LE(*position, LastElement() + step);
+      UNSAFE_TODO(DCHECK_LE(*position, LastElement() + step));
       DCHECK_GE(*position, Begin());
 
       // Adjust the size and capacity
@@ -84,13 +80,14 @@
       std::unique_ptr<char[], base::AlignedFreeDeleter> new_data(
           static_cast<char*>(base::AlignedAlloc(size * step, alignment)));
       size_t position_offset = *position - Begin();
-      *position = new_data.get() + position_offset;
+      *position = UNSAFE_TODO(new_data.get() + position_offset);
 
       // Copy the data before the inserted segment
-      memcpy(new_data.get(), data.get(), position_offset);
+      UNSAFE_TODO(memcpy(new_data.get(), data.get(), position_offset));
       // Copy the data after the inserted segment.
-      memcpy(new_data.get() + position_offset + count * step,
-             data.get() + position_offset, old_size * step - position_offset);
+      UNSAFE_TODO(memcpy(new_data.get() + position_offset + count * step,
+                         data.get() + position_offset,
+                         old_size * step - position_offset));
       data = std::move(new_data);
     }
 
@@ -110,9 +107,13 @@
     }
 
     char* Begin() const { return data.get(); }
-    char* End() const { return data.get() + size * step; }
-    char* LastElement() const { return data.get() + (size - 1) * step; }
-    char* ElementAt(size_t index) const { return data.get() + index * step; }
+    char* End() const { return UNSAFE_TODO(data.get() + size * step); }
+    char* LastElement() const {
+      return UNSAFE_TODO(data.get() + (size - 1) * step);
+    }
+    char* ElementAt(size_t index) const {
+      return UNSAFE_TODO(data.get() + index * step);
+    }
   };
 
   CharAllocator(size_t alignment, size_t element_size, size_t element_count)
@@ -318,7 +319,7 @@
     else
       item_iterator = nullptr;
   } else {
-    item_iterator += list.step;
+    UNSAFE_TODO(item_iterator += list.step);
   }
   return *this;
 }
@@ -343,7 +344,7 @@
       item_iterator = nullptr;
     }
   } else {
-    item_iterator -= list.step;
+    UNSAFE_TODO(item_iterator -= list.step);
   }
   return *this;
 }
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc
index fb99664..8189b989 100644
--- a/cc/metrics/frame_sequence_tracker_unittest.cc
+++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -2,17 +2,13 @@
 // 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 "cc/metrics/frame_sequence_tracker.h"
 
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/bind.h"
@@ -32,7 +28,7 @@
 
 const char* ParseNumber(const char* str, uint64_t* retvalue) {
   uint64_t number = 0;
-  for (; *str >= '0' && *str <= '9'; ++str) {
+  for (; *str >= '0' && *str <= '9'; UNSAFE_TODO(++str)) {
     number *= 10;
     number += *str - '0';
   }
@@ -134,7 +130,7 @@
     const uint64_t source_id = 1;
     viz::BeginFrameArgs last_activated_main_args;
     while (*str) {
-      const char command = *str++;
+      const char command = *UNSAFE_TODO(str++);
       uint64_t sequence = 0, dummy = 0, last_activated_main = 0;
       switch (command) {
         case 'b':
@@ -146,27 +142,27 @@
         case 's':
         case 'r':
           ASSERT_EQ(*str, '(') << command;
-          str = ParseNumber(++str, &sequence);
+          str = ParseNumber(UNSAFE_TODO(++str), &sequence);
           ASSERT_EQ(*str, ')');
-          ++str;
+          UNSAFE_TODO(++str);
           break;
 
         case 'N':
           ASSERT_EQ(*str, '(');
-          str = ParseNumber(++str, &dummy);
+          str = ParseNumber(UNSAFE_TODO(++str), &dummy);
           ASSERT_EQ(*str, ',');
-          str = ParseNumber(++str, &sequence);
+          str = ParseNumber(UNSAFE_TODO(++str), &sequence);
           ASSERT_EQ(*str, ')');
-          ++str;
+          UNSAFE_TODO(++str);
           break;
 
         case 'e':
           ASSERT_EQ(*str, '(');
-          str = ParseNumber(++str, &sequence);
+          str = ParseNumber(UNSAFE_TODO(++str), &sequence);
           ASSERT_EQ(*str, ',');
-          str = ParseNumber(++str, &last_activated_main);
+          str = ParseNumber(UNSAFE_TODO(++str), &last_activated_main);
           ASSERT_EQ(*str, ')');
-          ++str;
+          UNSAFE_TODO(++str);
           break;
 
         case 'R':
diff --git a/cc/metrics/lcd_text_metrics_reporter.cc b/cc/metrics/lcd_text_metrics_reporter.cc
index 8c99dd7..99eb2724 100644
--- a/cc/metrics/lcd_text_metrics_reporter.cc
+++ b/cc/metrics/lcd_text_metrics_reporter.cc
@@ -2,13 +2,9 @@
 // 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 "cc/metrics/lcd_text_metrics_reporter.h"
 
+#include "base/compiler_specific.h"
 #include "base/functional/function_ref.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
@@ -66,8 +62,9 @@
     const LayerTreeHostImpl* layer_tree_host_impl) {
   const char* client_name = GetClientNameForMetrics();
   // The metrics are for the renderer only.
-  if (!client_name || strcmp(client_name, "Renderer") != 0)
+  if (!client_name || UNSAFE_TODO(strcmp(client_name, "Renderer")) != 0) {
     return nullptr;
+  }
   return base::WrapUnique(new LCDTextMetricsReporter(layer_tree_host_impl));
 }
 
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc
index 5e92f32..3bb0158 100644
--- a/cc/paint/display_item_list_unittest.cc
+++ b/cc/paint/display_item_list_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 "cc/paint/display_item_list.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 #include <array>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/trace_event/traced_value.h"
 #include "base/values.h"
@@ -49,8 +45,10 @@
                       void* expected_pixels,
                       int width,
                       int height) {
-  if (memcmp(actual_pixels, expected_pixels, 4 * width * height) == 0)
+  if (UNSAFE_TODO(memcmp(actual_pixels, expected_pixels, 4 * width * height)) ==
+      0) {
     return true;
+  }
 
   SkImageInfo actual_info = SkImageInfo::MakeN32Premul(width, height);
   SkBitmap actual_bitmap;
diff --git a/cc/paint/paint_cache_unittest.cc b/cc/paint/paint_cache_unittest.cc
index eebe576..3698727b 100644
--- a/cc/paint/paint_cache_unittest.cc
+++ b/cc/paint/paint_cache_unittest.cc
@@ -2,13 +2,9 @@
 // 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 "cc/paint/paint_cache.h"
 
+#include "base/compiler_specific.h"
 #include "base/hash/hash.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -56,7 +52,7 @@
   ClientPaintCache::PurgedData purged_data;
   client_cache.Purge(&purged_data);
   EXPECT_EQ(client_cache.bytes_used(), kDefaultBudget);
-  const auto& ids = purged_data[static_cast<uint32_t>(GetType())];
+  const auto& ids = UNSAFE_TODO(purged_data[static_cast<uint32_t>(GetType())]);
   ASSERT_EQ(ids.size(), 2u);
   EXPECT_EQ(ids[0], 1u);
   EXPECT_EQ(ids[1], 2u);
diff --git a/cc/paint/paint_op_perftest.cc b/cc/paint/paint_op_perftest.cc
index c6d8a0f0..88e19ab6 100644
--- a/cc/paint/paint_op_perftest.cc
+++ b/cc/paint/paint_op_perftest.cc
@@ -2,13 +2,9 @@
 // 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 <utility>
 
+#include "base/compiler_specific.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "base/timer/lap_timer.h"
@@ -87,7 +83,7 @@
           break;
 
         remaining_read_bytes -= bytes_read;
-        to_read += bytes_read;
+        UNSAFE_TODO(to_read += bytes_read);
       }
 
       timer_.NextLap();
@@ -162,7 +158,7 @@
   SkTextBlobBuilder builder;
   int glyph_count = 5;
   const auto& run = builder.allocRun(font, glyph_count, 1.2f, 2.3f);
-  std::fill(run.glyphs, run.glyphs + glyph_count, 0);
+  std::fill(run.glyphs, UNSAFE_TODO(run.glyphs + glyph_count), 0);
   auto blob = builder.make();
 
   PaintFlags flags;
diff --git a/cc/paint/paint_op_writer_reader_unittest.cc b/cc/paint/paint_op_writer_reader_unittest.cc
index 21d2b16..3a312c0 100644
--- a/cc/paint/paint_op_writer_reader_unittest.cc
+++ b/cc/paint/paint_op_writer_reader_unittest.cc
@@ -2,13 +2,9 @@
 // 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 <vector>
 
+#include "base/compiler_specific.h"
 #include "cc/paint/paint_op_reader.h"
 #include "cc/paint/paint_op_writer.h"
 #include "cc/test/test_options_provider.h"
@@ -23,7 +19,7 @@
 
   char buffer[128];
   TestOptionsProvider options_provider;
-  memset(buffer, 0xa5, std::size(buffer));
+  UNSAFE_TODO(memset(buffer, 0xa5, std::size(buffer)));
   PaintOpWriter writer(buffer, std::size(buffer),
                        options_provider.serialize_options(),
                        /*enable_security_constraints*/ true);
@@ -56,7 +52,7 @@
 TEST(PaintOpWriterReaderTest, Vector) {
   char buffer[128];
   TestOptionsProvider options_provider;
-  memset(buffer, 0xa5, std::size(buffer));
+  UNSAFE_TODO(memset(buffer, 0xa5, std::size(buffer)));
   PaintOpWriter writer(buffer, std::size(buffer),
                        options_provider.serialize_options(),
                        /*enable_security_constraints*/ true);
@@ -85,7 +81,7 @@
 TEST(PaintOpWriterReaderTest, SkString) {
   char buffer[128];
   TestOptionsProvider options_provider;
-  memset(buffer, 0xa5, std::size(buffer));
+  UNSAFE_TODO(memset(buffer, 0xa5, std::size(buffer)));
   PaintOpWriter writer(buffer, std::size(buffer),
                        options_provider.serialize_options(),
                        /*enable_security_constraints=*/true);
@@ -107,7 +103,7 @@
 TEST(PaintOpWriterReaderTest, EmptySkString) {
   char buffer[128];
   TestOptionsProvider options_provider;
-  memset(buffer, 0xa5, std::size(buffer));
+  UNSAFE_TODO(memset(buffer, 0xa5, std::size(buffer)));
   PaintOpWriter writer(buffer, std::size(buffer),
                        options_provider.serialize_options(),
                        /*enable_security_constraints=*/true);
@@ -140,7 +136,7 @@
 TEST_P(PaintOpWriterReaderUniformTest, Uniforms) {
   char buffer[128];
   TestOptionsProvider options_provider;
-  memset(buffer, 0xa5, std::size(buffer));
+  UNSAFE_TODO(memset(buffer, 0xa5, std::size(buffer)));
   PaintOpWriter writer(buffer, std::size(buffer),
                        options_provider.serialize_options(),
                        /*enable_security_constraints=*/true);
diff --git a/cc/paint/render_surface_filters.cc b/cc/paint/render_surface_filters.cc
index de565f6..c784149a 100644
--- a/cc/paint/render_surface_filters.cc
+++ b/cc/paint/render_surface_filters.cc
@@ -2,17 +2,14 @@
 // 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 "cc/paint/render_surface_filters.h"
 
 #include <stddef.h>
+
 #include <algorithm>
 #include <utility>
 
-#include "cc/paint/render_surface_filters.h"
-
+#include "base/compiler_specific.h"
 #include "base/numerics/angle_conversions.h"
 #include "cc/paint/filter_operation.h"
 #include "cc/paint/filter_operations.h"
@@ -30,118 +27,131 @@
   // Spec implementation
   // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquivalent)
   // <feFunc[R|G|B] type="linear" slope="[amount]">
-  memset(matrix, 0, 20 * sizeof(float));
-  matrix[0] = matrix[6] = matrix[12] = amount;
-  matrix[18] = 1.f;
+  UNSAFE_TODO(memset(matrix, 0, 20 * sizeof(float)));
+  matrix[0] = UNSAFE_TODO(matrix[6]) = UNSAFE_TODO(matrix[12]) = amount;
+  UNSAFE_TODO(matrix[18]) = 1.f;
 }
 
 void GetSaturatingBrightnessMatrix(float amount, float matrix[20]) {
   // Legacy implementation used by internal clients.
   // <feFunc[R|G|B] type="linear" intercept="[amount]"/>
-  memset(matrix, 0, 20 * sizeof(float));
-  matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
-  matrix[4] = matrix[9] = matrix[14] = amount;
+  UNSAFE_TODO(memset(matrix, 0, 20 * sizeof(float)));
+  matrix[0] = UNSAFE_TODO(matrix[6]) = UNSAFE_TODO(matrix[12]) =
+      UNSAFE_TODO(matrix[18]) = 1.f;
+  UNSAFE_TODO(matrix[4]) = UNSAFE_TODO(matrix[9]) = UNSAFE_TODO(matrix[14]) =
+      amount;
 }
 
 void GetContrastMatrix(float amount, float matrix[20]) {
-  memset(matrix, 0, 20 * sizeof(float));
-  matrix[0] = matrix[6] = matrix[12] = amount;
-  matrix[4] = matrix[9] = matrix[14] = (-0.5f * amount + 0.5f);
-  matrix[18] = 1.f;
+  UNSAFE_TODO(memset(matrix, 0, 20 * sizeof(float)));
+  matrix[0] = UNSAFE_TODO(matrix[6]) = UNSAFE_TODO(matrix[12]) = amount;
+  UNSAFE_TODO(matrix[4]) = UNSAFE_TODO(matrix[9]) = UNSAFE_TODO(matrix[14]) =
+      (-0.5f * amount + 0.5f);
+  UNSAFE_TODO(matrix[18]) = 1.f;
 }
 
 void GetSaturateMatrix(float amount, float matrix[20]) {
   // Note, these values are computed to ensure MatrixNeedsClamping is false
   // for amount in [0..1]
   matrix[0] = 0.213f + 0.787f * amount;
-  matrix[1] = 0.715f - 0.715f * amount;
-  matrix[2] = 1.f - (matrix[0] + matrix[1]);
-  matrix[3] = matrix[4] = 0.f;
-  matrix[5] = 0.213f - 0.213f * amount;
-  matrix[6] = 0.715f + 0.285f * amount;
-  matrix[7] = 1.f - (matrix[5] + matrix[6]);
-  matrix[8] = matrix[9] = 0.f;
-  matrix[10] = 0.213f - 0.213f * amount;
-  matrix[11] = 0.715f - 0.715f * amount;
-  matrix[12] = 1.f - (matrix[10] + matrix[11]);
-  matrix[13] = matrix[14] = 0.f;
-  matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
-  matrix[18] = 1.f;
+  UNSAFE_TODO(matrix[1]) = 0.715f - 0.715f * amount;
+  UNSAFE_TODO(matrix[2]) = 1.f - (matrix[0] + UNSAFE_TODO(matrix[1]));
+  UNSAFE_TODO(matrix[3]) = UNSAFE_TODO(matrix[4]) = 0.f;
+  UNSAFE_TODO(matrix[5]) = 0.213f - 0.213f * amount;
+  UNSAFE_TODO(matrix[6]) = 0.715f + 0.285f * amount;
+  UNSAFE_TODO(matrix[7]) =
+      1.f - (UNSAFE_TODO(matrix[5]) + UNSAFE_TODO(matrix[6]));
+  UNSAFE_TODO(matrix[8]) = UNSAFE_TODO(matrix[9]) = 0.f;
+  UNSAFE_TODO(matrix[10]) = 0.213f - 0.213f * amount;
+  UNSAFE_TODO(matrix[11]) = 0.715f - 0.715f * amount;
+  UNSAFE_TODO(matrix[12]) =
+      1.f - (UNSAFE_TODO(matrix[10]) + UNSAFE_TODO(matrix[11]));
+  UNSAFE_TODO(matrix[13]) = UNSAFE_TODO(matrix[14]) = 0.f;
+  UNSAFE_TODO(matrix[15]) = UNSAFE_TODO(matrix[16]) = UNSAFE_TODO(matrix[17]) =
+      UNSAFE_TODO(matrix[19]) = 0.f;
+  UNSAFE_TODO(matrix[18]) = 1.f;
 }
 
 void GetHueRotateMatrix(float hue, float matrix[20]) {
   float cos_hue = cosf(base::DegToRad(hue));
   float sin_hue = sinf(base::DegToRad(hue));
   matrix[0] = 0.213f + cos_hue * 0.787f - sin_hue * 0.213f;
-  matrix[1] = 0.715f - cos_hue * 0.715f - sin_hue * 0.715f;
-  matrix[2] = 0.072f - cos_hue * 0.072f + sin_hue * 0.928f;
-  matrix[3] = matrix[4] = 0.f;
-  matrix[5] = 0.213f - cos_hue * 0.213f + sin_hue * 0.143f;
-  matrix[6] = 0.715f + cos_hue * 0.285f + sin_hue * 0.140f;
-  matrix[7] = 0.072f - cos_hue * 0.072f - sin_hue * 0.283f;
-  matrix[8] = matrix[9] = 0.f;
-  matrix[10] = 0.213f - cos_hue * 0.213f - sin_hue * 0.787f;
-  matrix[11] = 0.715f - cos_hue * 0.715f + sin_hue * 0.715f;
-  matrix[12] = 0.072f + cos_hue * 0.928f + sin_hue * 0.072f;
-  matrix[13] = matrix[14] = 0.f;
-  matrix[15] = matrix[16] = matrix[17] = 0.f;
-  matrix[18] = 1.f;
-  matrix[19] = 0.f;
+  UNSAFE_TODO(matrix[1]) = 0.715f - cos_hue * 0.715f - sin_hue * 0.715f;
+  UNSAFE_TODO(matrix[2]) = 0.072f - cos_hue * 0.072f + sin_hue * 0.928f;
+  UNSAFE_TODO(matrix[3]) = UNSAFE_TODO(matrix[4]) = 0.f;
+  UNSAFE_TODO(matrix[5]) = 0.213f - cos_hue * 0.213f + sin_hue * 0.143f;
+  UNSAFE_TODO(matrix[6]) = 0.715f + cos_hue * 0.285f + sin_hue * 0.140f;
+  UNSAFE_TODO(matrix[7]) = 0.072f - cos_hue * 0.072f - sin_hue * 0.283f;
+  UNSAFE_TODO(matrix[8]) = UNSAFE_TODO(matrix[9]) = 0.f;
+  UNSAFE_TODO(matrix[10]) = 0.213f - cos_hue * 0.213f - sin_hue * 0.787f;
+  UNSAFE_TODO(matrix[11]) = 0.715f - cos_hue * 0.715f + sin_hue * 0.715f;
+  UNSAFE_TODO(matrix[12]) = 0.072f + cos_hue * 0.928f + sin_hue * 0.072f;
+  UNSAFE_TODO(matrix[13]) = UNSAFE_TODO(matrix[14]) = 0.f;
+  UNSAFE_TODO(matrix[15]) = UNSAFE_TODO(matrix[16]) = UNSAFE_TODO(matrix[17]) =
+      0.f;
+  UNSAFE_TODO(matrix[18]) = 1.f;
+  UNSAFE_TODO(matrix[19]) = 0.f;
 }
 
 void GetInvertMatrix(float amount, float matrix[20]) {
-  memset(matrix, 0, 20 * sizeof(float));
-  matrix[0] = matrix[6] = matrix[12] = 1.f - 2.f * amount;
-  matrix[4] = matrix[9] = matrix[14] = amount;
-  matrix[18] = 1.f;
+  UNSAFE_TODO(memset(matrix, 0, 20 * sizeof(float)));
+  matrix[0] = UNSAFE_TODO(matrix[6]) = UNSAFE_TODO(matrix[12]) =
+      1.f - 2.f * amount;
+  UNSAFE_TODO(matrix[4]) = UNSAFE_TODO(matrix[9]) = UNSAFE_TODO(matrix[14]) =
+      amount;
+  UNSAFE_TODO(matrix[18]) = 1.f;
 }
 
 void GetOpacityMatrix(float amount, float matrix[20]) {
-  memset(matrix, 0, 20 * sizeof(float));
-  matrix[0] = matrix[6] = matrix[12] = 1.f;
-  matrix[18] = amount;
+  UNSAFE_TODO(memset(matrix, 0, 20 * sizeof(float)));
+  matrix[0] = UNSAFE_TODO(matrix[6]) = UNSAFE_TODO(matrix[12]) = 1.f;
+  UNSAFE_TODO(matrix[18]) = amount;
 }
 
 void GetGrayscaleMatrix(float amount, float matrix[20]) {
   // Note, these values are computed to ensure MatrixNeedsClamping is false
   // for amount in [0..1]
   matrix[0] = 0.2126f + 0.7874f * amount;
-  matrix[1] = 0.7152f - 0.7152f * amount;
-  matrix[2] = 1.f - (matrix[0] + matrix[1]);
-  matrix[3] = matrix[4] = 0.f;
+  UNSAFE_TODO(matrix[1]) = 0.7152f - 0.7152f * amount;
+  UNSAFE_TODO(matrix[2]) = 1.f - (matrix[0] + UNSAFE_TODO(matrix[1]));
+  UNSAFE_TODO(matrix[3]) = UNSAFE_TODO(matrix[4]) = 0.f;
 
-  matrix[5] = 0.2126f - 0.2126f * amount;
-  matrix[6] = 0.7152f + 0.2848f * amount;
-  matrix[7] = 1.f - (matrix[5] + matrix[6]);
-  matrix[8] = matrix[9] = 0.f;
+  UNSAFE_TODO(matrix[5]) = 0.2126f - 0.2126f * amount;
+  UNSAFE_TODO(matrix[6]) = 0.7152f + 0.2848f * amount;
+  UNSAFE_TODO(matrix[7]) =
+      1.f - (UNSAFE_TODO(matrix[5]) + UNSAFE_TODO(matrix[6]));
+  UNSAFE_TODO(matrix[8]) = UNSAFE_TODO(matrix[9]) = 0.f;
 
-  matrix[10] = 0.2126f - 0.2126f * amount;
-  matrix[11] = 0.7152f - 0.7152f * amount;
-  matrix[12] = 1.f - (matrix[10] + matrix[11]);
-  matrix[13] = matrix[14] = 0.f;
+  UNSAFE_TODO(matrix[10]) = 0.2126f - 0.2126f * amount;
+  UNSAFE_TODO(matrix[11]) = 0.7152f - 0.7152f * amount;
+  UNSAFE_TODO(matrix[12]) =
+      1.f - (UNSAFE_TODO(matrix[10]) + UNSAFE_TODO(matrix[11]));
+  UNSAFE_TODO(matrix[13]) = UNSAFE_TODO(matrix[14]) = 0.f;
 
-  matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
-  matrix[18] = 1.f;
+  UNSAFE_TODO(matrix[15]) = UNSAFE_TODO(matrix[16]) = UNSAFE_TODO(matrix[17]) =
+      UNSAFE_TODO(matrix[19]) = 0.f;
+  UNSAFE_TODO(matrix[18]) = 1.f;
 }
 
 void GetSepiaMatrix(float amount, float matrix[20]) {
   matrix[0] = 0.393f + 0.607f * amount;
-  matrix[1] = 0.769f - 0.769f * amount;
-  matrix[2] = 0.189f - 0.189f * amount;
-  matrix[3] = matrix[4] = 0.f;
+  UNSAFE_TODO(matrix[1]) = 0.769f - 0.769f * amount;
+  UNSAFE_TODO(matrix[2]) = 0.189f - 0.189f * amount;
+  UNSAFE_TODO(matrix[3]) = UNSAFE_TODO(matrix[4]) = 0.f;
 
-  matrix[5] = 0.349f - 0.349f * amount;
-  matrix[6] = 0.686f + 0.314f * amount;
-  matrix[7] = 0.168f - 0.168f * amount;
-  matrix[8] = matrix[9] = 0.f;
+  UNSAFE_TODO(matrix[5]) = 0.349f - 0.349f * amount;
+  UNSAFE_TODO(matrix[6]) = 0.686f + 0.314f * amount;
+  UNSAFE_TODO(matrix[7]) = 0.168f - 0.168f * amount;
+  UNSAFE_TODO(matrix[8]) = UNSAFE_TODO(matrix[9]) = 0.f;
 
-  matrix[10] = 0.272f - 0.272f * amount;
-  matrix[11] = 0.534f - 0.534f * amount;
-  matrix[12] = 0.131f + 0.869f * amount;
-  matrix[13] = matrix[14] = 0.f;
+  UNSAFE_TODO(matrix[10]) = 0.272f - 0.272f * amount;
+  UNSAFE_TODO(matrix[11]) = 0.534f - 0.534f * amount;
+  UNSAFE_TODO(matrix[12]) = 0.131f + 0.869f * amount;
+  UNSAFE_TODO(matrix[13]) = UNSAFE_TODO(matrix[14]) = 0.f;
 
-  matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0.f;
-  matrix[18] = 1.f;
+  UNSAFE_TODO(matrix[15]) = UNSAFE_TODO(matrix[16]) = UNSAFE_TODO(matrix[17]) =
+      UNSAFE_TODO(matrix[19]) = 0.f;
+  UNSAFE_TODO(matrix[18]) = 1.f;
 }
 
 sk_sp<PaintFilter> CreateMatrixImageFilter(const float matrix[20],
diff --git a/cc/paint/skottie_transfer_cache_entry_unittest.cc b/cc/paint/skottie_transfer_cache_entry_unittest.cc
index e3a3fc1c..55bdf31 100644
--- a/cc/paint/skottie_transfer_cache_entry_unittest.cc
+++ b/cc/paint/skottie_transfer_cache_entry_unittest.cc
@@ -2,18 +2,15 @@
 // 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 "cc/paint/skottie_transfer_cache_entry.h"
 
 #include <memory>
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/memory/scoped_refptr.h"
-#include "cc/paint/skottie_transfer_cache_entry.h"
 #include "cc/paint/skottie_wrapper.h"
 #include "cc/test/lottie_test_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,8 +22,9 @@
   std::vector<uint8_t> a_data(kLottieDataWithoutAssets1.length());
   a_data.assign(
       reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()),
-      reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()) +
-          kLottieDataWithoutAssets1.length());
+      UNSAFE_TODO(
+          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()) +
+          kLottieDataWithoutAssets1.length()));
 
   scoped_refptr<SkottieWrapper> skottie =
       SkottieWrapper::UnsafeCreateSerializable(std::move(a_data));
diff --git a/cc/paint/skottie_wrapper_unittest.cc b/cc/paint/skottie_wrapper_unittest.cc
index 0a9c449..be040de 100644
--- a/cc/paint/skottie_wrapper_unittest.cc
+++ b/cc/paint/skottie_wrapper_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 "cc/paint/skottie_wrapper.h"
 
 #include <cstdint>
@@ -14,6 +9,7 @@
 #include <string_view>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
@@ -68,9 +64,10 @@
 
 TEST(SkottieWrapperTest, LoadsValidLottieFileNonSerializable) {
   scoped_refptr<SkottieWrapper> skottie =
-      SkottieWrapper::UnsafeCreateNonSerializable(base::span<const uint8_t>(
-          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()),
-          kLottieDataWithoutAssets1.length()));
+      SkottieWrapper::UnsafeCreateNonSerializable(UNSAFE_TODO(
+          base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(
+                                        kLottieDataWithoutAssets1.data()),
+                                    kLottieDataWithoutAssets1.length())));
   EXPECT_TRUE(skottie->is_valid());
 }
 
@@ -78,30 +75,34 @@
   scoped_refptr<SkottieWrapper> skottie =
       SkottieWrapper::UnsafeCreateSerializable(std::vector<uint8_t>(
           reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()),
-          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()) +
-              kLottieDataWithoutAssets1.length()));
+          UNSAFE_TODO(reinterpret_cast<const uint8_t*>(
+                          kLottieDataWithoutAssets1.data()) +
+                      kLottieDataWithoutAssets1.length())));
   EXPECT_TRUE(skottie->is_valid());
 }
 
 TEST(SkottieWrapperTest, DetectsInvalidLottieFile) {
   static constexpr std::string_view kInvalidJson = "this is invalid json";
   scoped_refptr<SkottieWrapper> skottie =
-      SkottieWrapper::UnsafeCreateNonSerializable(base::span<const uint8_t>(
-          reinterpret_cast<const uint8_t*>(kInvalidJson.data()),
-          kInvalidJson.length()));
+      SkottieWrapper::UnsafeCreateNonSerializable(
+          UNSAFE_TODO(base::span<const uint8_t>(
+              reinterpret_cast<const uint8_t*>(kInvalidJson.data()),
+              kInvalidJson.length())));
   EXPECT_FALSE(skottie->is_valid());
 }
 
 TEST(SkottieWrapperTest, IdMatchesForSameLottieFile) {
   scoped_refptr<SkottieWrapper> skottie_1 =
-      SkottieWrapper::UnsafeCreateNonSerializable(base::span<const uint8_t>(
-          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()),
-          kLottieDataWithoutAssets1.length()));
+      SkottieWrapper::UnsafeCreateNonSerializable(UNSAFE_TODO(
+          base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(
+                                        kLottieDataWithoutAssets1.data()),
+                                    kLottieDataWithoutAssets1.length())));
   scoped_refptr<SkottieWrapper> skottie_2 =
       SkottieWrapper::UnsafeCreateSerializable(std::vector<uint8_t>(
           reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()),
-          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()) +
-              kLottieDataWithoutAssets1.length()));
+          UNSAFE_TODO(reinterpret_cast<const uint8_t*>(
+                          kLottieDataWithoutAssets1.data()) +
+                      kLottieDataWithoutAssets1.length())));
   ASSERT_TRUE(skottie_1->is_valid());
   ASSERT_TRUE(skottie_2->is_valid());
   EXPECT_THAT(skottie_1->id(), Eq(skottie_2->id()));
@@ -109,13 +110,15 @@
 
 TEST(SkottieWrapperTest, IdDoesNotMatchForDifferentLottieFile) {
   scoped_refptr<SkottieWrapper> skottie_1 =
-      SkottieWrapper::UnsafeCreateNonSerializable(base::span<const uint8_t>(
-          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets1.data()),
-          kLottieDataWithoutAssets1.length()));
+      SkottieWrapper::UnsafeCreateNonSerializable(UNSAFE_TODO(
+          base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(
+                                        kLottieDataWithoutAssets1.data()),
+                                    kLottieDataWithoutAssets1.length())));
   scoped_refptr<SkottieWrapper> skottie_2 =
-      SkottieWrapper::UnsafeCreateNonSerializable(base::span<const uint8_t>(
-          reinterpret_cast<const uint8_t*>(kLottieDataWithoutAssets2.data()),
-          kLottieDataWithoutAssets2.length()));
+      SkottieWrapper::UnsafeCreateNonSerializable(UNSAFE_TODO(
+          base::span<const uint8_t>(reinterpret_cast<const uint8_t*>(
+                                        kLottieDataWithoutAssets2.data()),
+                                    kLottieDataWithoutAssets2.length())));
   ASSERT_TRUE(skottie_1->is_valid());
   ASSERT_TRUE(skottie_2->is_valid());
   EXPECT_THAT(skottie_1->id(), Ne(skottie_2->id()));
@@ -123,9 +126,10 @@
 
 TEST(SkottieWrapperTest, LoadsImageAssetsMetadata) {
   scoped_refptr<SkottieWrapper> skottie =
-      SkottieWrapper::UnsafeCreateNonSerializable(base::span<const uint8_t>(
-          reinterpret_cast<const uint8_t*>(kLottieDataWith2Assets.data()),
-          kLottieDataWith2Assets.length()));
+      SkottieWrapper::UnsafeCreateNonSerializable(
+          UNSAFE_TODO(base::span<const uint8_t>(
+              reinterpret_cast<const uint8_t*>(kLottieDataWith2Assets.data()),
+              kLottieDataWith2Assets.length())));
   ASSERT_TRUE(skottie->is_valid());
   SkottieResourceMetadataMap metadata = skottie->GetImageAssetMetadata();
   EXPECT_THAT(
diff --git a/cc/paint/transfer_cache_unittest.cc b/cc/paint/transfer_cache_unittest.cc
index 5ec7994a..f1b0d4e 100644
--- a/cc/paint/transfer_cache_unittest.cc
+++ b/cc/paint/transfer_cache_unittest.cc
@@ -2,14 +2,10 @@
 // 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 <vector>
 
 #include "base/command_line.h"
+#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "cc/paint/image_transfer_cache_entry.h"
 #include "cc/paint/raw_memory_transfer_cache_entry.h"
@@ -75,7 +71,7 @@
     uint32_t size = entry.SerializedSize();
     void* data = context_support->MapTransferCacheEntry(size);
     ASSERT_TRUE(data);
-    entry.Serialize(base::span(static_cast<uint8_t*>(data), size));
+    entry.Serialize(UNSAFE_TODO(base::span(static_cast<uint8_t*>(data), size)));
     context_support->UnmapAndCreateTransferCacheEntry(entry.UnsafeType(),
                                                       entry.Id());
   }
diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc
index 61a3395..a9bf0def 100644
--- a/cc/raster/raster_buffer_provider_perftest.cc
+++ b/cc/raster/raster_buffer_provider_perftest.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 "cc/raster/raster_buffer_provider.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 
 #include <array>
 
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/test_simple_task_runner.h"
@@ -51,11 +47,11 @@
   // Overridden from gpu::gles2::GLES2Interface:
   void GenBuffers(GLsizei n, GLuint* buffers) override {
     for (GLsizei i = 0; i < n; ++i)
-      buffers[i] = 1u;
+      UNSAFE_TODO(buffers[i]) = 1u;
   }
   void GenTextures(GLsizei n, GLuint* textures) override {
     for (GLsizei i = 0; i < n; ++i)
-      textures[i] = 1u;
+      UNSAFE_TODO(textures[i]) = 1u;
   }
   void GetIntegerv(GLenum pname, GLint* params) override {
     if (pname == GL_MAX_TEXTURE_SIZE)
@@ -63,7 +59,7 @@
   }
   void GenQueriesEXT(GLsizei n, GLuint* queries) override {
     for (GLsizei i = 0; i < n; ++i)
-      queries[i] = 1u;
+      UNSAFE_TODO(queries[i]) = 1u;
   }
   void GetQueryObjectuivEXT(GLuint query,
                             GLenum pname,
@@ -77,7 +73,7 @@
     // Copy the data over after setting the data to ensure alignment.
     gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO,
                                    gpu::CommandBufferId(), 0);
-    memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
+    UNSAFE_TODO(memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)));
   }
 };
 
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 3bfbac5..534d396 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -2,12 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/scheduler/scheduler_state_machine.h"
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "cc/scheduler/scheduler.h"
 
 #include <stddef.h>
@@ -19,6 +13,7 @@
 
 #include "base/auto_reset.h"
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
@@ -34,6 +29,7 @@
 #include "cc/metrics/begin_main_frame_metrics.h"
 #include "cc/metrics/event_metrics.h"
 #include "cc/metrics/frame_sequence_tracker_collection.h"
+#include "cc/scheduler/scheduler_state_machine.h"
 #include "cc/test/fake_compositor_frame_reporting_controller.h"
 #include "cc/test/scheduler_test_common.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -94,8 +90,9 @@
 
   int ActionIndex(const char* action) const {
     for (size_t i = 0; i < actions_.size(); i++)
-      if (!strcmp(actions_[i], action))
+      if (!UNSAFE_TODO(strcmp(actions_[i], action))) {
         return base::checked_cast<int>(i);
+      }
     return -1;
   }
 
diff --git a/cc/test/fake_paint_image_generator.cc b/cc/test/fake_paint_image_generator.cc
index cab5177..06e7080 100644
--- a/cc/test/fake_paint_image_generator.cc
+++ b/cc/test/fake_paint_image_generator.cc
@@ -2,17 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <array>
-
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "cc/test/fake_paint_image_generator.h"
 
+#include <array>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 
 namespace cc {
@@ -110,8 +105,9 @@
   uint8_t* src_plane_memory = image_backing_memory_.data();
   int num_planes = pixmaps.numPlanes();
   for (int i = 0; i < num_planes; ++i) {
-    memcpy(pixmaps.plane(i).writable_addr(), src_plane_memory, plane_sizes[i]);
-    src_plane_memory += plane_sizes[i];
+    UNSAFE_TODO(memcpy(pixmaps.plane(i).writable_addr(), src_plane_memory,
+                       plane_sizes[i]));
+    UNSAFE_TODO(src_plane_memory += plane_sizes[i]);
   }
   if (!base::Contains(frames_decoded_count_, frame_index)) {
     frames_decoded_count_[frame_index] = 1;
diff --git a/cc/test/layer_tree_json_parser.cc b/cc/test/layer_tree_json_parser.cc
index eeeaf5d5..31f9972 100644
--- a/cc/test/layer_tree_json_parser.cc
+++ b/cc/test/layer_tree_json_parser.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 "cc/test/layer_tree_json_parser.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/test/values_test_util.h"
 #include "base/values.h"
 #include "cc/layers/layer.h"
@@ -176,7 +172,7 @@
       return nullptr;
     }
 
-    transform[i] = (*transform_list)[i].GetDouble();
+    UNSAFE_TODO(transform[i]) = (*transform_list)[i].GetDouble();
   }
 
   new_layer->SetTransform(gfx::Transform::ColMajorF(transform));
diff --git a/cc/test/skia_common.cc b/cc/test/skia_common.cc
index 60ee386..38b1c71 100644
--- a/cc/test/skia_common.cc
+++ b/cc/test/skia_common.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 "cc/test/skia_common.h"
 
 #include <stddef.h>
@@ -18,6 +13,7 @@
 
 #include "base/base_paths.h"
 #include "base/check.h"
+#include "base/compiler_specific.h"
 #include "base/containers/heap_array.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
@@ -92,12 +88,12 @@
 
   auto pixels_a = base::HeapArray<unsigned char>::Uninit(pixel_size);
   auto pixels_b = base::HeapArray<unsigned char>::Uninit(pixel_size);
-  memset(pixels_a.data(), 0, pixel_size);
-  memset(pixels_b.data(), 0, pixel_size);
+  UNSAFE_TODO(memset(pixels_a.data(), 0, pixel_size));
+  UNSAFE_TODO(memset(pixels_b.data(), 0, pixel_size));
   DrawDisplayList(pixels_a.data(), layer_rect, list_a);
   DrawDisplayList(pixels_b.data(), layer_rect, list_b);
 
-  return !memcmp(pixels_a.data(), pixels_b.data(), pixel_size);
+  return !UNSAFE_TODO(memcmp(pixels_a.data(), pixels_b.data(), pixel_size));
 }
 
 Region ImageRectsToRegion(const DiscardableImageMap::Rects& rects) {
diff --git a/cc/test/test_options_provider.cc b/cc/test/test_options_provider.cc
index 1a844400..23f23d9 100644
--- a/cc/test/test_options_provider.cc
+++ b/cc/test/test_options_provider.cc
@@ -2,16 +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 "cc/test/test_options_provider.h"
 
 #include <limits>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "cc/paint/paint_op_writer.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
@@ -120,11 +116,13 @@
       false /* needs_mips */, std::nullopt);
   const uint32_t data_size = cache_entry.SerializedSize();
   auto data = PaintOpWriter::AllocateAlignedBuffer<uint8_t>(data_size);
-  if (!cache_entry.Serialize(base::span<uint8_t>(data.get(), data_size))) {
+  if (!cache_entry.Serialize(
+          UNSAFE_TODO(base::span<uint8_t>(data.get(), data_size)))) {
     return ScopedResult();
   }
 
-  CreateEntryDirect(entry_key, base::span<uint8_t>(data.get(), data_size));
+  CreateEntryDirect(entry_key,
+                    UNSAFE_TODO(base::span<uint8_t>(data.get(), data_size)));
 
   return ScopedResult(DecodedDrawImage(
       image_id, nullptr, SkSize::MakeEmpty(), draw_image.scale(),
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index b5ac15ce..91915c5 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_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 "cc/tiles/gpu_image_decode_cache.h"
 
 #include <algorithm>
@@ -18,6 +13,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
@@ -193,7 +189,7 @@
   void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override {
     transfer_cache_helper_->CreateEntryDirect(
         MakeEntryKey(type, id),
-        base::span(mapped_entry_.get(), mapped_entry_size_));
+        UNSAFE_TODO(base::span(mapped_entry_.get(), mapped_entry_size_)));
     mapped_entry_ = nullptr;
     mapped_entry_size_ = 0;
   }
@@ -275,7 +271,7 @@
   }
   void DeleteTextures(GLsizei n, const GLuint* textures) override {
     for (GLsizei i = 0; i < n; i++) {
-      discardable_manager_->DeleteTexture(textures[i]);
+      discardable_manager_->DeleteTexture(UNSAFE_TODO(textures[i]));
     }
     TestGLES2Interface::DeleteTextures(n, textures);
   }
@@ -733,7 +729,7 @@
             draw_image, static_cast<YUVIndex>(i));
       }
       ASSERT_TRUE(uploaded_plane);
-      EXPECT_EQ(plane_sizes[i], uploaded_plane->dimensions());
+      UNSAFE_TODO(EXPECT_EQ(plane_sizes[i], uploaded_plane->dimensions()));
       EXPECT_EQ(expected_color_type, uploaded_plane->colorType());
       if (expected_cs && use_transfer_cache_) {
         EXPECT_TRUE(
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 53eebc1..a46d399 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -647,6 +647,9 @@
   const viz::LocalSurfaceId& GetCurrentLocalSurfaceId() const {
     return child_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
   }
+  const viz::LocalSurfaceId& target_local_surface_id() const {
+    return target_local_surface_id_;
+  }
 
   LayerTreeImpl* active_tree() { return active_tree_.get(); }
   const LayerTreeImpl* active_tree() const { return active_tree_.get(); }
diff --git a/cc/trees/occlusion_unittest.cc b/cc/trees/occlusion_unittest.cc
index 0fcbdff..60eec9d 100644
--- a/cc/trees/occlusion_unittest.cc
+++ b/cc/trees/occlusion_unittest.cc
@@ -2,17 +2,13 @@
 // 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 "cc/trees/occlusion.h"
 
 #include <stddef.h>
 
 #include <array>
 
+#include "base/compiler_specific.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -58,25 +54,29 @@
   });
 
   Occlusion no_occlusion;
-  EXPECT_OCCLUSION(no_occlusion, rects, false, false, false, false);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(no_occlusion, rects, false, false, false, false));
 
   Occlusion all_occluded_outside(
       gfx::Transform(), SimpleEnclosedRegion(20, 20), SimpleEnclosedRegion());
-  EXPECT_OCCLUSION(all_occluded_outside, rects, true, true, true, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(all_occluded_outside, rects, true, true, true, true));
 
   Occlusion all_occluded_inside(
       gfx::Transform(), SimpleEnclosedRegion(), SimpleEnclosedRegion(20, 20));
-  EXPECT_OCCLUSION(all_occluded_inside, rects, true, true, true, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(all_occluded_inside, rects, true, true, true, true));
 
   Occlusion all_occluded_mixed(gfx::Transform(),
                                SimpleEnclosedRegion(10, 20),
                                SimpleEnclosedRegion(10, 0, 10, 20));
-  EXPECT_OCCLUSION(all_occluded_mixed, rects, true, true, true, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(all_occluded_mixed, rects, true, true, true, true));
 
   Occlusion some_occluded(gfx::Transform(),
                           SimpleEnclosedRegion(10, 10),
                           SimpleEnclosedRegion(10, 10, 10, 10));
-  EXPECT_OCCLUSION(some_occluded, rects, true, false, false, true);
+  UNSAFE_TODO(EXPECT_OCCLUSION(some_occluded, rects, true, false, false, true));
 }
 
 TEST(OcclusionTest, IsOccludedScaled) {
@@ -97,15 +97,19 @@
       half_scale, SimpleEnclosedRegion(10, 10), SimpleEnclosedRegion());
   Occlusion all_occluded_outside_double(
       double_scale, SimpleEnclosedRegion(40, 40), SimpleEnclosedRegion());
-  EXPECT_OCCLUSION(all_occluded_outside_half, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_outside_double, rects, true, true, true, true);
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_outside_half, rects, true, true,
+                               true, true));
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_outside_double, rects, true, true,
+                               true, true));
 
   Occlusion all_occluded_inside_half(
       half_scale, SimpleEnclosedRegion(), SimpleEnclosedRegion(10, 10));
   Occlusion all_occluded_inside_double(
       double_scale, SimpleEnclosedRegion(), SimpleEnclosedRegion(40, 40));
-  EXPECT_OCCLUSION(all_occluded_inside_half, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_inside_double, rects, true, true, true, true);
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_inside_half, rects, true, true,
+                               true, true));
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_inside_double, rects, true, true,
+                               true, true));
 
   Occlusion all_occluded_mixed_half(half_scale,
                                     SimpleEnclosedRegion(5, 10),
@@ -113,16 +117,20 @@
   Occlusion all_occluded_mixed_double(double_scale,
                                       SimpleEnclosedRegion(20, 40),
                                       SimpleEnclosedRegion(20, 0, 20, 40));
-  EXPECT_OCCLUSION(all_occluded_mixed_half, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_mixed_double, rects, true, true, true, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(all_occluded_mixed_half, rects, true, true, true, true));
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_mixed_double, rects, true, true,
+                               true, true));
 
   Occlusion some_occluded_half(
       half_scale, SimpleEnclosedRegion(5, 5), SimpleEnclosedRegion(5, 5, 5, 5));
   Occlusion some_occluded_double(double_scale,
                                  SimpleEnclosedRegion(20, 20),
                                  SimpleEnclosedRegion(20, 20, 20, 20));
-  EXPECT_OCCLUSION(some_occluded_half, rects, true, false, false, true);
-  EXPECT_OCCLUSION(some_occluded_double, rects, true, false, false, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(some_occluded_half, rects, true, false, false, true));
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(some_occluded_double, rects, true, false, false, true));
 }
 
 TEST(OcclusionTest, IsOccludedTranslated) {
@@ -143,15 +151,19 @@
       move_left, SimpleEnclosedRegion(-100, 0, 20, 20), SimpleEnclosedRegion());
   Occlusion all_occluded_outside_down(
       move_down, SimpleEnclosedRegion(0, 100, 20, 20), SimpleEnclosedRegion());
-  EXPECT_OCCLUSION(all_occluded_outside_left, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_outside_down, rects, true, true, true, true);
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_outside_left, rects, true, true,
+                               true, true));
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_outside_down, rects, true, true,
+                               true, true));
 
   Occlusion all_occluded_inside_left(
       move_left, SimpleEnclosedRegion(), SimpleEnclosedRegion(-100, 0, 20, 20));
   Occlusion all_occluded_inside_down(
       move_down, SimpleEnclosedRegion(), SimpleEnclosedRegion(0, 100, 20, 20));
-  EXPECT_OCCLUSION(all_occluded_inside_left, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_inside_down, rects, true, true, true, true);
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_inside_left, rects, true, true,
+                               true, true));
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_inside_down, rects, true, true,
+                               true, true));
 
   Occlusion all_occluded_mixed_left(move_left,
                                     SimpleEnclosedRegion(-100, 0, 10, 20),
@@ -159,8 +171,10 @@
   Occlusion all_occluded_mixed_down(move_down,
                                     SimpleEnclosedRegion(0, 100, 10, 20),
                                     SimpleEnclosedRegion(10, 100, 10, 20));
-  EXPECT_OCCLUSION(all_occluded_mixed_left, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_mixed_down, rects, true, true, true, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(all_occluded_mixed_left, rects, true, true, true, true));
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(all_occluded_mixed_down, rects, true, true, true, true));
 
   Occlusion some_occluded_left(move_left,
                                SimpleEnclosedRegion(-100, 0, 10, 10),
@@ -168,8 +182,10 @@
   Occlusion some_occluded_down(move_down,
                                SimpleEnclosedRegion(0, 100, 10, 10),
                                SimpleEnclosedRegion(10, 110, 10, 10));
-  EXPECT_OCCLUSION(some_occluded_left, rects, true, false, false, true);
-  EXPECT_OCCLUSION(some_occluded_down, rects, true, false, false, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(some_occluded_left, rects, true, false, false, true));
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(some_occluded_down, rects, true, false, false, true));
 }
 
 TEST(OcclusionTest, IsOccludedScaledAfterConstruction) {
@@ -196,8 +212,10 @@
   Occlusion all_occluded_outside_double =
       all_occluded_outside.GetOcclusionWithGivenDrawTransform(double_transform);
 
-  EXPECT_OCCLUSION(all_occluded_outside_half, rects, true, true, true, true);
-  EXPECT_OCCLUSION(all_occluded_outside_double, rects, true, true, true, true);
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_outside_half, rects, true, true,
+                               true, true));
+  UNSAFE_TODO(EXPECT_OCCLUSION(all_occluded_outside_double, rects, true, true,
+                               true, true));
 
   Occlusion some_occluded(gfx::Transform(),
                           SimpleEnclosedRegion(5, 5),
@@ -211,8 +229,10 @@
   Occlusion some_occluded_double =
       some_occluded.GetOcclusionWithGivenDrawTransform(double_transform);
 
-  EXPECT_OCCLUSION(some_occluded_half, rects, true, false, false, true);
-  EXPECT_OCCLUSION(some_occluded_double, rects, true, false, false, true);
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(some_occluded_half, rects, true, false, false, true));
+  UNSAFE_TODO(
+      EXPECT_OCCLUSION(some_occluded_double, rects, true, false, false, true));
 }
 
 TEST(OcclusionTest, GetUnoccludedContentRectNoTransform) {
diff --git a/chrome/VERSION b/chrome/VERSION
index 6a8e9c62..0e73cd7 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=140
 MINOR=0
-BUILD=7315
+BUILD=7316
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 69781bb..739844c 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -325,6 +325,7 @@
       "//base:flagged_apis_java",
       "//base:service_loader_java",
       "//base:task_executor_java",
+      "//base:virtual_document_path_java",
       "//base/version_info/android:version_constants_java",
       "//cc:cc_java",
       "//cc/mojom:mojom_java",
@@ -442,8 +443,6 @@
       "//chrome/browser/password_manager/android:java",
       "//chrome/browser/password_manager/android:settings_interface_java",
       "//chrome/browser/password_manager/android:utils_java",
-      "//chrome/browser/password_manager/android/access_loss:enums_java",
-      "//chrome/browser/password_manager/android/access_loss:helper_java",
       "//chrome/browser/password_manager/android/account_storage_toggle:java",
       "//chrome/browser/password_manager/android/bottom_sheet:java",
       "//chrome/browser/password_manager/android/grouped_affiliations:java",
@@ -741,6 +740,7 @@
       "//services/network/public/mojom:mojom_java",
       "//services/network/public/mojom:mojom_proxy_config_java",
       "//services/network/public/mojom:url_loader_base_java",
+      "//services/on_device_model/android:java",
       "//services/service_manager/public/java:service_manager_java",
       "//services/service_manager/public/mojom:mojom_java",
       "//services/shape_detection:shape_detection_java",
@@ -941,7 +941,10 @@
     ]
 
     if (is_desktop_android) {
-      deps += [ "//chrome/browser/ui/browser_window/internal:java" ]
+      deps += [
+        "//chrome/browser/ui/android/extensions/windowing/internal:java",
+        "//chrome/browser/ui/browser_window/internal:java",
+      ]
     }
   }
 
@@ -1191,6 +1194,10 @@
     if (enable_extensions_core) {
       deps += [ "//chrome/browser/ui/android/extensions:junit" ]
     }
+
+    if (is_desktop_android) {
+      deps += [ "//chrome/browser/ui/browser_window/internal:junit" ]
+    }
   }
 
   # Files used by chrome integration and unit javatests.
@@ -2385,7 +2392,6 @@
       "//chrome/browser/gesturenav/android:javatests",
       "//chrome/browser/password_check/android:test_java",
       "//chrome/browser/password_manager/android:javatests",
-      "//chrome/browser/password_manager/android/access_loss:javatests",
       "//chrome/browser/password_manager/android/bottom_sheet:javatests",
       "//chrome/browser/picture_in_picture/test:javatests",
       "//chrome/browser/recent_tabs/internal:recent_tabs_javatests",
@@ -3208,7 +3214,6 @@
       "java/src/org/chromium/chrome/browser/password_manager/AutoSigninSnackbarController.java",
       "java/src/org/chromium/chrome/browser/password_manager/Credential.java",
       "java/src/org/chromium/chrome/browser/password_manager/CredentialLeakDialogBridge.java",
-      "java/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridge.java",
       "java/src/org/chromium/chrome/browser/password_manager/PasswordCheckupLauncher.java",
       "java/src/org/chromium/chrome/browser/password_manager/PasswordManagerErrorMessageHelperBridge.java",
       "java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index dfb9826..698302a 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -520,7 +520,6 @@
   "java/res/layout/manage_sync_settings_bottom_bar.xml",
   "java/res/layout/material_tooltip.xml",
   "java/res/layout/multiline_spinner_item.xml",
-  "java/res/layout/mv_tiles_container.xml",
   "java/res/layout/mv_tiles_layout.xml",
   "java/res/layout/navigation_bubble.xml",
   "java/res/layout/navigation_sheet.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 8a9d7432..ac4bec2 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -847,7 +847,6 @@
   "java/src/org/chromium/chrome/browser/password_manager/Credential.java",
   "java/src/org/chromium/chrome/browser/password_manager/CredentialLeakDialogBridge.java",
   "java/src/org/chromium/chrome/browser/password_manager/GooglePasswordManagerUIProvider.java",
-  "java/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridge.java",
   "java/src/org/chromium/chrome/browser/password_manager/PasswordCheckupLauncher.java",
   "java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogContents.java",
   "java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogCoordinator.java",
diff --git a/chrome/android/features/create_stripped_java_factory.py b/chrome/android/features/create_stripped_java_factory.py
index 8b38c2e..7ac5202 100755
--- a/chrome/android/features/create_stripped_java_factory.py
+++ b/chrome/android/features/create_stripped_java_factory.py
@@ -207,6 +207,14 @@
   with open(options.input, 'r') as f:
     content = f.read()
 
+  if '<@Nullable' in content:
+    sys.stderr.write("""
+Error: @Nullable annotations inside generic types are not supported.
+Please remove them from {file_path}.
+See https://crbug.com/433562519 for details.
+""".format(file_path=options.input))
+    sys.exit(1)
+
   java_ast = javalang.parse.parse(content)
   assert len(java_ast.types) == 1, 'Can only process Java files with one class'
   clazz = java_ast.types[0]
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index 76296888..9841a2e 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -55,6 +55,7 @@
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
     "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+    "//third_party/androidx:androidx_browser_browser_java",
     "//third_party/androidx:androidx_core_core_java",
     "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//third_party/androidx:androidx_viewpager_viewpager_java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java
index 886228d..2a77e2cd 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/AutofillKeyboardAccessoryViewBridge.java
@@ -4,7 +4,13 @@
 
 package org.chromium.chrome.browser.keyboard_accessory;
 
+import android.app.Activity;
+import android.net.Uri;
+import android.text.style.ClickableSpan;
+import android.view.View;
+
 import androidx.annotation.Nullable;
+import androidx.browser.customtabs.CustomTabsIntent;
 
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JNINamespace;
@@ -20,14 +26,17 @@
 import org.chromium.components.autofill.SuggestionType;
 import org.chromium.ui.DropdownItem;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.text.SpanApplier;
 import org.chromium.url.GURL;
 
+import java.lang.ref.WeakReference;
 import java.util.List;
 
 /** JNI call glue between C++ (AutofillKeyboardAccessoryViewImpl) and Java objects. */
 @JNINamespace("autofill")
 public class AutofillKeyboardAccessoryViewBridge implements AutofillDelegate {
     private long mNativeAutofillKeyboardAccessory;
+    private WeakReference<Activity> mActivity;
     private @Nullable ObservableSupplier<ManualFillingComponent> mManualFillingComponentSupplier;
     private @Nullable ManualFillingComponent mManualFillingComponent;
     private final PropertyProvider<List<AutofillSuggestion>> mChipProvider =
@@ -73,9 +82,27 @@
                 .onDeletionDialogClosed(mNativeAutofillKeyboardAccessory, confirmed);
     }
 
+    private CharSequence createMessageWithLink(String body, String link) {
+        if (mActivity.get() == null) {
+            return body;
+        }
+        ClickableSpan span =
+                new ClickableSpan() {
+                    @Override
+                    public void onClick(View view) {
+                        assert mActivity.get() != null;
+                        new CustomTabsIntent.Builder()
+                                .setShowTitle(true)
+                                .build()
+                                .launchUrl(mActivity.get(), Uri.parse(link));
+                    }
+                };
+        return SpanApplier.applySpans(body, new SpanApplier.SpanInfo("<link>", "</link>", span));
+    }
+
     /**
-     * Initializes this object.
-     * This function should be called at most one time.
+     * Initializes this object. This function should be called at most one time.
+     *
      * @param nativeAutofillKeyboardAccessory Handle to the native counterpart.
      * @param windowAndroid The window on which to show the suggestions.
      */
@@ -88,6 +115,7 @@
             connectToFillingComponent(currentFillingComponent);
         }
 
+        mActivity = windowAndroid.getActivity();
         mNativeAutofillKeyboardAccessory = nativeAutofillKeyboardAccessory;
     }
 
@@ -117,15 +145,33 @@
         mChipProvider.notifyObservers(suggestions);
     }
 
+    /**
+     * Shows a deletion confirmation dialog for a KeyboardAccessory suggestion.
+     *
+     * @param title The title for the dialog.
+     * @param body The body of the dialog. This may contain &lt;link&gt; tags, which will be linked
+     *     to {@code bodyLink}.
+     * @param bodyLink If not empty, this string will be used as the link within the &lt;link&gt;
+     *     tags in the body.
+     * @param confirmButtonText The text displayed on the confirmation button (e.g., "Remove",
+     *     "Delete").
+     */
     @CalledByNative
     private void confirmDeletion(
             @JniType("std::u16string") String title,
             @JniType("std::u16string") String body,
+            @JniType("std::u16string") String bodyLink,
             @JniType("std::u16string") String confirmButtonText) {
+
+        CharSequence message = body;
+        if (!bodyLink.isEmpty() && mActivity.get() != null) {
+            message = createMessageWithLink(body, bodyLink);
+        }
+
         assert mManualFillingComponent != null;
         mManualFillingComponent.confirmDeletionOperation(
                 title,
-                body,
+                message,
                 confirmButtonText,
                 () -> this.onDeletionDialogClosed(/* confirmed= */ true),
                 () -> this.onDeletionDialogClosed(/* confirmed= */ false));
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
index f25583e..f20878b 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingCoordinator.java
@@ -216,7 +216,7 @@
     @Override
     public void confirmDeletionOperation(
             String title,
-            String message,
+            CharSequence message,
             String confirmButtonText,
             Runnable confirmedCallback,
             Runnable declinedCallback) {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
index bbd7b86..5b4b5f4 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -714,7 +714,7 @@
 
     void confirmDeletionOperation(
             String title,
-            String message,
+            CharSequence message,
             String confirmButtonText,
             Runnable confirmedCallback,
             Runnable declinedCallback) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index c836be09..a6d667b9 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -3157,7 +3157,8 @@
         if (tabId != Tab.INVALID_TAB_ID) {
             TabGroupModelFilter filter = mCurrentTabGroupModelFilterSupplier.get();
             Tab tab = filter.getTabModel().getTabById(tabId);
-            assumeNonNull(tab);
+            if (tab == null) return;
+
             boolean isInTabGroup = filter.tabGroupExists(tab.getTabGroupId());
             final @Nullable @TabGroupColorId Integer tabGroupColor =
                     isInTabGroup ? filter.getTabGroupColorWithFallback(tab.getTabGroupId()) : null;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java
index d270897..d6072d35 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPanePublicTransitTest.java
@@ -31,7 +31,7 @@
 import org.chromium.chrome.test.transit.hub.RegularTabSwitcherStation;
 import org.chromium.chrome.test.transit.hub.TabSwitcherListEditorFacility;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.ui.base.DeviceFormFactor;
 
@@ -54,7 +54,7 @@
         WebPageStation firstPage = mCtaTestRule.startOnBlankPage();
         ChromeTabbedActivity cta = mCtaTestRule.getActivity();
 
-        PageStation page = firstPage;
+        CtaPageStation page = firstPage;
         for (int i = 1; i < 10; i++) {
             page = page.openNewTabFast();
         }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java
index 9ee45468..3a83c25 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupListBottomSheetTest.java
@@ -31,7 +31,7 @@
 import org.chromium.chrome.test.transit.hub.TabSwitcherGroupCardFacility;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 
 /**
@@ -163,12 +163,12 @@
         assertFinalDestination(finalStation);
     }
 
-    private static void assertTabGroupsExist(PageStation pageStation) {
+    private static void assertTabGroupsExist(CtaPageStation pageStation) {
         int tabGroupCount = pageStation.getTabGroupModelFilter().getTabGroupCount();
         assertTrue(tabGroupCount > 0);
     }
 
-    private static void assertCurrentTabIsNotInGroup(PageStation pageStation) {
+    private static void assertCurrentTabIsNotInGroup(CtaPageStation pageStation) {
         Tab currentTab = pageStation.getTab();
         assertNull(currentTab.getTabGroupId());
     }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
index bfbc83b..723b0be 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
@@ -64,7 +64,7 @@
 import org.chromium.chrome.test.transit.hub.UndoSnackbarFacility;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabThumbnailsCapturedCarryOn;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
@@ -132,7 +132,7 @@
 
     /** Enters the regular Tab Switcher, making sure all tabs have a thumbnail. */
     private RegularTabSwitcherStation enterRegularHtsWithThumbnailChecking(
-            PageStation currentStation) {
+            CtaPageStation currentStation) {
         return currentStation
                 .openRegularTabSwitcherAnd()
                 .pickUpCarryOnAnd(
@@ -143,7 +143,7 @@
 
     /** Enters the Incognito Tab Switcher, making sure all tabs have a thumbnail. */
     private IncognitoTabSwitcherStation enterIncognitoHtsWithThumbnailChecking(
-            PageStation currentStation) {
+            CtaPageStation currentStation) {
         return currentStation
                 .openIncognitoTabSwitcherAnd()
                 .pickUpCarryOnAnd(
@@ -656,9 +656,9 @@
         assertFinalDestination(ntp);
     }
 
-    private <T extends PageStation> T roundtripToHTSWithThumbnailChecks(
+    private <T extends CtaPageStation> T roundtripToHTSWithThumbnailChecks(
             T page,
-            Supplier<PageStation.Builder<T>> destinationBuiderFactory,
+            Supplier<CtaPageStation.Builder<T>> destinationBuiderFactory,
             Runnable resetHTSStateOnUiThread,
             boolean canGarbageCollectBitmaps) {
         RegularTabSwitcherStation tabSwitcher = enterRegularHtsWithThumbnailChecking(page);
diff --git a/chrome/android/java/res/layout/mv_tiles_container.xml b/chrome/android/java/res/layout/mv_tiles_container.xml
deleted file mode 100644
index 462abce..0000000
--- a/chrome/android/java/res/layout/mv_tiles_container.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-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.
--->
-
-<!-- A site suggestion tile. -->
-<FrameLayout android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/mv_tiles_container"
-    android:visibility="gone"
-    android:orientation="vertical"
-    android:layout_gravity="center_horizontal"
-    android:layout_marginTop="@dimen/mvt_container_top_margin"
-    android:layout_marginLeft="@dimen/mvt_container_lateral_margin"
-    android:layout_marginRight="@dimen/mvt_container_lateral_margin"
-    android:paddingTop="@dimen/mvt_container_top_padding"
-    android:paddingBottom="@dimen/mvt_container_bottom_padding"
-    android:background="@drawable/home_surface_ui_background"
-    app:layout_scrollFlags="scroll">
-
-  <ViewStub
-      android:id="@+id/mv_tiles_layout_stub"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout="@layout/mv_tiles_layout" />
-</FrameLayout>
diff --git a/chrome/android/java/res/layout/mv_tiles_layout.xml b/chrome/android/java/res/layout/mv_tiles_layout.xml
index 9eb24ef..f573311 100644
--- a/chrome/android/java/res/layout/mv_tiles_layout.xml
+++ b/chrome/android/java/res/layout/mv_tiles_layout.xml
@@ -8,6 +8,9 @@
 <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:background="@drawable/home_surface_ui_background"
+    android:paddingTop="@dimen/mvt_container_top_padding"
+    android:paddingBottom="@dimen/mvt_container_bottom_padding"
     android:scrollbars="none">
 
   <org.chromium.chrome.browser.suggestions.tile.MostVisitedTilesLayout
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index 69f80f8..3b9c59c3 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -47,15 +47,15 @@
         android:layout_marginTop="16dp"
         android:visibility="gone"/>
 
-    <!-- Middle spacer -->
-    <View
-        android:id="@+id/ntp_middle_spacer"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="0"
-        android:visibility="invisible" />
-
-    <!-- Insertion point of the SiteSectionView, see NewTabPageLayout#insertSiteSection() -->
+    <ViewStub
+        android:id="@+id/mv_tiles_layout_stub"
+        android:inflatedId="@+id/mv_tiles_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/mvt_container_top_margin"
+        android:layout_marginLeft="@dimen/mvt_container_lateral_margin"
+        android:layout_marginRight="@dimen/mvt_container_lateral_margin"
+        android:layout="@layout/mv_tiles_layout" />
 
     <ViewStub
         android:id="@+id/home_modules_recycler_view_stub"
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index d782c5aa..d63f084 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -132,6 +132,7 @@
     <item type="id" name="pin_tab_menu_id" />
     <item type="id" name="unpin_tab_menu_id" />
     <item type="id" name="new_window_menu_id" />
+    <item type="id" name="new_incognito_window_menu_id" />
     <item type="id" name="move_to_other_window_menu_id" />
     <item type="id" name="manage_all_windows_menu_id" />
     <item type="id" name="divider_line_id" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java
index 4849f393..ec53d46 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplicationImpl.java
@@ -63,8 +63,7 @@
             // Only load the native library early for non-test builds since some tests use the
             // "--disable-native-initialization" switch, and the CommandLine is not initialized at
             // this point to check.
-            if (!BuildConfig.IS_FOR_TEST
-                    && !ChromeFeatureList.sSkipIsolatedSplitPreload.isEnabled()) {
+            if (!BuildConfig.IS_FOR_TEST) {
                 // Kick off library loading in a separate thread so it's ready when we need it.
                 new Thread(() -> LibraryLoader.getInstance().ensureInitialized()).start();
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 2c6ca29..6988927 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -1525,12 +1525,13 @@
     /**
      * Creates an Intent that tells Chrome to bring an Activity for a particular Tab back to the
      * foreground.
+     *
      * @param tabId The id of the Tab to bring to the foreground.
      * @param bringToFrontSource The source of the bring to front Intent, used for gathering
-     *         metrics.
+     *     metrics.
      * @return Created Intent or null if this operation isn't possible.
      */
-    public static @Nullable Intent createTrustedBringTabToFrontIntent(
+    public static Intent createTrustedBringTabToFrontIntent(
             int tabId, @BringToFrontSource int bringToFrontSource) {
         Context context = ContextUtils.getApplicationContext();
         Intent intent = new Intent(context, ChromeLauncherActivity.class);
@@ -1594,10 +1595,8 @@
     public static void bringTabToFront(Tab tab) {
         Intent newIntent =
                 createTrustedBringTabToFrontIntent(tab.getId(), BringToFrontSource.SEARCH_ACTIVITY);
-        if (newIntent != null) {
-            newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            IntentUtils.safeStartActivity(ContextUtils.getApplicationContext(), newIntent);
-        }
+        newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        IntentUtils.safeStartActivity(ContextUtils.getApplicationContext(), newIntent);
     }
 
     /** Create a LoadUrlParams for handling a VIEW intent. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragment.java
index d816be3..a60b10b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragment.java
@@ -159,13 +159,15 @@
         HashSet<Pair<String, String>> issuersAndProductDescriptions = new HashSet<>();
 
         // List the card for product terms redirect if:
-        // 1. The card has a valid product term url.
-        // 2. Same issuer and card product combination is not listed before.
+        // 1. The card is eligible for benefits.
+        // 2. The card has a valid product term url.
+        // 3. Same issuer and card product combination is not listed before.
         for (CreditCard card : mPersonalDataManager.getCreditCardsForSettings()) {
             Pair<String, String> issuerAndProductDescriptionPair =
                     Pair.create(card.getIssuerId(), card.getProductDescription());
 
-            if (issuersAndProductDescriptions.contains(issuerAndProductDescriptionPair)
+            if (!mPersonalDataManager.isCardEligibleForBenefits(card.getGUID())
+                    || issuersAndProductDescriptions.contains(issuerAndProductDescriptionPair)
                     || GURL.isEmptyOrInvalid(card.getProductTermsUrl())) {
                 continue;
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
index b3187f9..8a927db2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -7,7 +7,6 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -22,7 +21,6 @@
 import org.chromium.build.annotations.IdentifierNameString;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
-import org.chromium.chrome.browser.language.GlobalAppLocaleController;
 import org.chromium.chrome.modules.on_demand.OnDemandModule;
 
 /**
@@ -158,8 +156,16 @@
     }
 
     @Override
-    protected void performBrowserProcessPreloading(Context context, boolean blockingLoad) {
-        SplitPreloader.PreloadHooks hooks =
+    protected void performBrowserProcessPreloading(Context context) {
+        // The chrome split has a large amount of code, which can slow down startup. Loading
+        // this in the background allows us to do this in parallel with startup tasks which do
+        // not depend on code in the chrome split.
+        sSplitPreloader = new SplitPreloader(context);
+        // If the chrome module is not enabled or isolated splits are not supported (e.g. in Android
+        // N), the onComplete function will run immediately so it must handle the case where the
+        // base context of the application has not been set yet.
+        sSplitPreloader.preload(
+                CHROME_SPLIT_NAME,
                 new SplitPreloader.PreloadHooks() {
                     @Override
                     public void runImmediatelyInBackgroundThread(Context chromeContext) {
@@ -202,13 +208,6 @@
                             BundleUtils.replaceClassLoader(
                                     SplitChromeApplication.this, chromeContext.getClassLoader());
                             JNIUtils.setDefaultClassLoader(chromeContext.getClassLoader());
-
-                            if (GlobalAppLocaleController.getInstance().isOverridden()) {
-                                Configuration config =
-                                        GlobalAppLocaleController.getInstance()
-                                                .getOverrideConfig(chromeContext);
-                                chromeContext = chromeContext.createConfigurationContext(config);
-                            }
                             // Resources holds a reference to a ClassLoader. Make our Application's
                             // getResources() return a reference to the Chrome split's resources
                             // since there are a spots where ContextUtils.getApplicationContext()
@@ -221,26 +220,7 @@
                     public Context createIsolatedSplitContext(String name) {
                         return createContextForSplitNoWait(name);
                     }
-                };
-
-        if (blockingLoad) {
-            Context chromeContext = hooks.createIsolatedSplitContext(CHROME_SPLIT_NAME);
-            hooks.runInUiThread(chromeContext);
-        } else {
-            // The chrome split has a large amount of code, which can slow down startup. Loading
-            // this in the background allows us to do this in parallel with startup tasks which do
-            // not depend on code in the chrome split.
-            sSplitPreloader = new SplitPreloader(context);
-            // If the chrome module is not enabled or isolated splits are not supported (e.g. in
-            // Android N), the onComplete function will run immediately so it must handle the case
-            // where the base context of the application has not been set yet.
-            sSplitPreloader.preload(CHROME_SPLIT_NAME, hooks);
-        }
-    }
-
-    @Override
-    protected void performBrowserProcessPreloading(Context context) {
-        performBrowserProcessPreloading(context, false);
+                });
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
index 5a359850..e83ee76 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
@@ -76,10 +76,6 @@
     private Supplier<Impl> mImplSupplier;
     private @Nullable Impl mImpl;
     private @Nullable ServiceTracingProxyProvider mServiceTracingProxyProvider;
-    // This doesn't work in Monochrome, since we try to load the WebView library as well when
-    // loading Chrome's library, and WebView requires attachBaseContext to have finished before
-    // you may attempt to load it's library. See crbug.com/390730928.
-    protected boolean mPreloadLibraryAttachBaseContext = true;
 
     /**
      * Holds the implementation of application logic. Will be called by {@link
@@ -201,7 +197,7 @@
 
         maybeInitProcessType();
 
-        if (isBrowserProcess && !ChromeFeatureList.sSkipIsolatedSplitPreload.isEnabled()) {
+        if (isBrowserProcess) {
             performBrowserProcessPreloading(context);
         }
 
@@ -270,11 +266,6 @@
             CustomAssertionHandler.installPreNativeHandler(factory);
         }
 
-        // Skipping tests since some use "--disable-native-initialization", and some tests manually
-        // test loading the native library themselves.
-        if (mPreloadLibraryAttachBaseContext) {
-            maybeInitChromeSplitAndPreloadNativeLibrary();
-        }
         TraceEvent.end(ATTACH_BASE_CONTEXT_EVENT);
     }
 
@@ -285,21 +276,9 @@
         // they use under-the-hood) does not work until after it returns.
         FontPreloadingWorkaround.maybeInstallWorkaround(this);
         MemoryPressureMonitor.INSTANCE.registerComponentCallbacks();
-        if (!mPreloadLibraryAttachBaseContext) {
-            maybeInitChromeSplitAndPreloadNativeLibrary();
-        }
         getImpl().onCreate();
     }
 
-    private void maybeInitChromeSplitAndPreloadNativeLibrary() {
-        if (isBrowserProcess()
-                && ChromeFeatureList.sSkipIsolatedSplitPreload.isEnabled()
-                && !BuildConfig.IS_FOR_TEST) {
-            new Thread(() -> LibraryLoader.getInstance().loadNow()).start();
-            performBrowserProcessPreloading(this, true);
-        }
-    }
-
     @Override
     public void onTrimMemory(int level) {
         super.onTrimMemory(level);
@@ -341,8 +320,6 @@
      */
     protected void performBrowserProcessPreloading(Context context) {}
 
-    protected void performBrowserProcessPreloading(Context context, boolean blockingLoad) {}
-
     public boolean isWebViewProcess() {
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
index 5d1f5b9d..2649b02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
@@ -36,11 +36,6 @@
 
     public SplitMonochromeApplication() {
         super(sImplClassName);
-        // Ensure that we don't try to load the native library until after attachBaseContext, since
-        // Monochrome attempts to call loadWebViewNativeLibraryFromPackage, which will fail until
-        // ActivityThread has an application set on it, which happens after attachBaseContext
-        // finishes. See crbug.com/390730928.
-        mPreloadLibraryAttachBaseContext = false;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitPreloader.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitPreloader.java
index b0abc6f..e08fa04 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitPreloader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitPreloader.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.base;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.os.SystemClock;
 
 import androidx.collection.SimpleArrayMap;
@@ -16,6 +17,7 @@
 import org.chromium.base.task.TaskTraits;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.language.GlobalAppLocaleController;
 
 /**
  * Handles preloading split Contexts on a background thread. Loading a new isolated split Context
@@ -103,6 +105,11 @@
                 } else {
                     context = BundleUtils.createIsolatedSplitContext(mName);
                 }
+                if (GlobalAppLocaleController.getInstance().isOverridden()) {
+                    Configuration config =
+                            GlobalAppLocaleController.getInstance().getOverrideConfig(context);
+                    context = context.createConfigurationContext(config);
+                }
                 return context;
             }
             return mContext;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java
index b71cb5d..ffa9f61 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java
@@ -16,7 +16,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.TerminationStatus;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.build.annotations.NullMarked;
@@ -88,8 +87,6 @@
                     }
                     assumeNonNull(messagePayload.getAsString());
                     mPostMessageBackend.onPostMessage(messagePayload.getAsString(), bundle);
-                    RecordHistogram.recordBooleanHistogram(
-                            "CustomTabs.PostMessage.OnMessage", true);
                 };
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
index 5a8c1757..a1eb962 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
@@ -32,7 +32,6 @@
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.fullscreen.BrowserControlsManager;
 import org.chromium.chrome.browser.gesturenav.OverscrollGlowCoordinator;
 import org.chromium.chrome.browser.layouts.CompositorModelChangeProcessor;
@@ -694,14 +693,7 @@
 
                     @Override
                     public void onBackgroundColorChanged(Tab tab, int color) {
-                        // The NavBarColorMatchesTabBackground increases the frequency of these
-                        // notifications, so Chrome should use a more targeted method to limit
-                        // performance impact.
-                        if (ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()) {
-                            updateLayoutTabBackgroundColor(tab.getId());
-                        } else {
-                            initLayoutTabFromHost(tab.getId());
-                        }
+                        updateLayoutTabBackgroundColor(tab.getId());
                     }
 
                     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
index 377bbd5c..063ff96 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/FullscreenVideoPictureInPictureController.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.media;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.PictureInPictureParams;
@@ -14,7 +16,6 @@
 import android.os.SystemClock;
 import android.util.Rational;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
@@ -23,6 +24,8 @@
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
@@ -41,6 +44,7 @@
 import java.util.Set;
 
 /** A controller for entering Picture in Picture mode with fullscreen videos. */
+@NullMarked
 public class FullscreenVideoPictureInPictureController {
     private static final String TAG = "VideoPersist";
     private static final int AUTO_PIP_UPDATE_DELAY = 500 /* msec */;
@@ -94,7 +98,7 @@
     /** Current observers, if any. */
     @Nullable DismissActivityOnTabChangeObserver mActivityTabObserver;
 
-    @Nullable FullscreenManager.Observer mFullscreenListener;
+    FullscreenManager.@Nullable Observer mFullscreenListener;
 
     private final Activity mActivity;
     private final ActivityTabProvider mActivityTabProvider;
@@ -317,13 +321,13 @@
         final Tab activityTab = mActivityTabProvider.get();
 
         // We don't want InfoBars displaying while in PiP, they cover too much content.
-        getInfoBarContainerForTab(activityTab).setHidden(true);
+        assumeNonNull(getInfoBarContainerForTab(activityTab)).setHidden(true);
 
         mOnLeavePipCallbacks.add(
                 () -> {
                     Log.i(TAG, "Running Picture-in-picture exit callbacks");
                     webContents.setHasPersistentVideo(false);
-                    getInfoBarContainerForTab(activityTab).setHidden(false);
+                    assumeNonNull(getInfoBarContainerForTab(activityTab)).setHidden(false);
                 });
 
         // Setup observers to dismiss the Activity on events that should end PiP.  In auto-enter
@@ -353,7 +357,7 @@
         dismissActivityIfNeeded(mActivity, MetricsEndReason.RESUME);
     }
 
-    private static Rect getVideoBounds(WebContents webContents, Activity activity) {
+    private static @Nullable Rect getVideoBounds(WebContents webContents, Activity activity) {
         Rect rect = webContents.getFullscreenVideoSize();
         if (rect == null || rect.width() == 0 || rect.height() == 0) return null;
 
@@ -587,8 +591,8 @@
     private class DismissActivityOnTabEventObserver extends EmptyTabObserver {
         private final Activity mActivity;
         private final Tab mTab;
-        private WebContents mWebContents;
-        private DismissActivityOnWebContentsObserver mWebContentsObserver;
+        private @Nullable WebContents mWebContents;
+        private @Nullable DismissActivityOnWebContentsObserver mWebContentsObserver;
 
         public DismissActivityOnTabEventObserver(Activity activity, Tab tab) {
             mActivity = activity;
@@ -663,10 +667,10 @@
     }
 
     /** A class to dismiss the Activity when the tab changes. */
-    private class DismissActivityOnTabChangeObserver implements Callback<Tab> {
+    private class DismissActivityOnTabChangeObserver implements Callback<@Nullable Tab> {
         private final Activity mActivity;
-        private Tab mCurrentTab;
-        private DismissActivityOnTabEventObserver mTabEventObserver;
+        private @Nullable Tab mCurrentTab;
+        private @Nullable DismissActivityOnTabEventObserver mTabEventObserver;
 
         private DismissActivityOnTabChangeObserver(Activity activity) {
             mActivity = activity;
@@ -692,7 +696,7 @@
         }
 
         @Override
-        public void onResult(Tab tab) {
+        public void onResult(@Nullable Tab tab) {
             if (mCurrentTab == tab) return;
 
             // If we're switching tabs, including to the case of "no tab", then get rid of the
@@ -770,7 +774,7 @@
 
     /** Protected to allow tests to override, since mocking statics is error-prone. */
     @VisibleForTesting
-    /* package */ InfoBarContainer getInfoBarContainerForTab(Tab tab) {
+    /* package */ @Nullable InfoBarContainer getInfoBarContainerForTab(@Nullable Tab tab) {
         return InfoBarContainer.get(tab);
     }
 
@@ -789,9 +793,8 @@
      * MediaSession's static getter.
      */
     @VisibleForTesting
-    /* package */ @Nullable
-    MediaSession getMediaSession() {
-        // This works if `getWebContents()` is null.
+    /* package */ @Nullable MediaSession getMediaSession() {
+        if (getWebContents() == null) return null;
         return MediaSession.fromWebContents(getWebContents());
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java
index 01f42bf..483b5fed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java
@@ -9,6 +9,7 @@
 import org.jni_zero.NativeMethods;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.content_public.browser.WebContents;
 
 /**
@@ -18,31 +19,26 @@
 @NullMarked
 public class MediaCaptureDevicesDispatcherAndroid {
     public static boolean isCapturingAudio(WebContents webContents) {
-        if (webContents == null) return false;
         return MediaCaptureDevicesDispatcherAndroidJni.get().isCapturingAudio(webContents);
     }
 
     public static boolean isCapturingVideo(WebContents webContents) {
-        if (webContents == null) return false;
         return MediaCaptureDevicesDispatcherAndroidJni.get().isCapturingVideo(webContents);
     }
 
     public static boolean isCapturingTab(WebContents webContents) {
-        if (webContents == null) return false;
         return MediaCaptureDevicesDispatcherAndroidJni.get().isCapturingTab(webContents);
     }
 
     public static boolean isCapturingWindow(WebContents webContents) {
-        if (webContents == null) return false;
         return MediaCaptureDevicesDispatcherAndroidJni.get().isCapturingWindow(webContents);
     }
 
     public static boolean isCapturingScreen(WebContents webContents) {
-        if (webContents == null) return false;
         return MediaCaptureDevicesDispatcherAndroidJni.get().isCapturingScreen(webContents);
     }
 
-    public static void notifyStopped(WebContents webContents) {
+    public static void notifyStopped(@Nullable WebContents webContents) {
         if (webContents == null) return;
         MediaCaptureDevicesDispatcherAndroidJni.get().notifyStopped(webContents);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationServiceImpl.java
index 65147a8a..ea74e03 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationServiceImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationServiceImpl.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.media;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.Manifest;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -14,7 +16,6 @@
 import android.os.IBinder;
 import android.util.SparseIntArray;
 
-import androidx.annotation.Nullable;
 import androidx.core.app.ActivityCompat;
 
 import org.chromium.base.ContextUtils;
@@ -22,6 +23,9 @@
 import org.chromium.base.IntentUtils;
 import org.chromium.base.Log;
 import org.chromium.base.shared_preferences.SharedPreferencesManager;
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.app.tabwindow.TabWindowManagerSingleton;
@@ -54,6 +58,7 @@
 import java.util.TreeMap;
 
 /** Service that creates/destroys the WebRTC notification when media capture starts/stops. */
+@NullMarked
 public class MediaCaptureNotificationServiceImpl extends MediaCaptureNotificationService.Impl {
     private static final String TAG = "MediaCapture";
     private static final String ACTION_MEDIA_CAPTURE_UPDATE =
@@ -76,6 +81,7 @@
 
     private boolean mStartedForegroundService;
 
+    @Initializer
     @Override
     public void onCreate() {
         mNotificationManager = BaseNotificationManagerProxyFactory.create();
@@ -102,7 +108,7 @@
     }
 
     @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
+    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
         if (intent == null || intent.getExtras() == null) {
             cancelPreviousWebRtcNotifications();
             getService().stopSelf();
@@ -147,6 +153,7 @@
     /**
      * Updates the extisting notification or creates one if none exist for the provided
      * notificationId and mediaType.
+     *
      * @param notificationId Unique id of the notification.
      * @param mediaType Media type of the notification.
      * @param url Url of the current webrtc call.
@@ -155,7 +162,7 @@
     private void updateNotification(
             int notificationId,
             @MediaType int mediaType,
-            String url,
+            @Nullable String url,
             boolean isIncognito,
             int startId) {
         if (doesNotificationExist(notificationId)
@@ -180,7 +187,8 @@
                 final int tabId = getTabIdFromNotificationId(notificationId);
                 final Tab tab = TabWindowManagerSingleton.getInstance().getTabById(tabId);
                 if (tab != null) {
-                    WindowAndroid window = tab.getWebContents().getTopLevelNativeWindow();
+                    WindowAndroid window =
+                            assumeNonNull(tab.getWebContents()).getTopLevelNativeWindow();
                     MediaCaptureOverlayController overlayController =
                             MediaCaptureOverlayController.from(window);
                     if (overlayController != null) {
@@ -211,7 +219,10 @@
     }
 
     private void createNotification(
-            int notificationId, @MediaType int mediaType, String url, boolean isIncognito) {
+            int notificationId,
+            @MediaType int mediaType,
+            @Nullable String url,
+            boolean isIncognito) {
         final String channelId =
                 MediaCaptureNotificationUtil.isCapture(mediaType)
                         ? ChromeChannelDefinitions.ChannelId.SCREEN_CAPTURE
@@ -269,7 +280,8 @@
             final int tabId = getTabIdFromNotificationId(notificationId);
             final Tab tab = TabWindowManagerSingleton.getInstance().getTabById(tabId);
             if (tab != null) {
-                WindowAndroid window = tab.getWebContents().getTopLevelNativeWindow();
+                WindowAndroid window =
+                        assumeNonNull(tab.getWebContents()).getTopLevelNativeWindow();
                 MediaCaptureOverlayController overlayController =
                         MediaCaptureOverlayController.from(window);
                 if (overlayController != null) {
@@ -349,7 +361,7 @@
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
+    public @Nullable IBinder onBind(Intent intent) {
         return null;
     }
 
@@ -419,10 +431,9 @@
         intent.putExtra(NOTIFICATION_ID_EXTRA, nofticationId);
         intent.putExtra(NOTIFICATION_MEDIA_URL_EXTRA, url.getSpec());
         intent.putExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, mediaType);
-        if (TabWindowManagerSingleton.getInstance().getTabById(tabId) != null) {
-            intent.putExtra(
-                    NOTIFICATION_MEDIA_IS_INCOGNITO,
-                    TabWindowManagerSingleton.getInstance().getTabById(tabId).isIncognito());
+        Tab tab = TabWindowManagerSingleton.getInstance().getTabById(tabId);
+        if (tab != null) {
+            intent.putExtra(NOTIFICATION_MEDIA_IS_INCOGNITO, tab.isIncognito());
         }
         try {
             context.startService(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaLauncherActivity.java
index cee0ab4b..a5952cc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaLauncherActivity.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.media;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Intent;
@@ -14,6 +16,7 @@
 import org.chromium.base.BuildInfo;
 import org.chromium.base.IntentUtils;
 import org.chromium.base.Log;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 
@@ -23,6 +26,7 @@
  * The MediaLauncherActivity handles media-viewing Intents from other apps. It takes the given
  * content:// URI from the Intent and properly routes it to a media-viewing CustomTabActivity.
  */
+@NullMarked
 public class MediaLauncherActivity extends Activity {
     private static final String TAG = "MediaLauncher";
 
@@ -30,7 +34,7 @@
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        Intent input = IntentUtils.sanitizeIntent(getIntent());
+        Intent input = assumeNonNull(IntentUtils.sanitizeIntent(getIntent()));
         Uri contentUri = input.getData();
         String mimeType = getMIMEType(contentUri);
 
@@ -60,13 +64,13 @@
         try {
             startActivity(intent);
         } catch (SecurityException e) {
-            Log.w(TAG, "Cannot open content URI: " + contentUri.toString(), e);
+            Log.w(TAG, "Cannot open content URI: " + contentUri, e);
         }
 
         finish();
     }
 
-    private String getMIMEType(Uri uri) {
+    private @Nullable String getMIMEType(@Nullable Uri uri) {
         if (uri == null) {
             return "";
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
index b4abc571..18f8299e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
@@ -28,6 +28,8 @@
 import org.chromium.base.SysUtils;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.CustomTabsUiType;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
@@ -37,6 +39,7 @@
 import java.util.Locale;
 
 /** A class containing some utility static methods. */
+@NullMarked
 public class MediaViewerUtils {
     private static final String DEFAULT_MIME_TYPE = "*/*";
     private static final String MIMETYPE_AUDIO = "audio";
@@ -47,18 +50,19 @@
 
     /**
      * Creates an Intent that allows viewing the given file in an internal media viewer.
-     * @param displayUri               URI to display to the user, ideally in file:// form.
-     * @param contentUri               content:// URI pointing at the file.
-     * @param mimeType                 MIME type of the file.
+     *
+     * @param displayUri URI to display to the user, ideally in file:// form.
+     * @param contentUri content:// URI pointing at the file.
+     * @param mimeType MIME type of the file.
      * @param allowExternalAppHandlers Whether the viewer should allow the user to open with another
-     *                                 app.
-     * @param allowShareAction         Whether the view should allow the share action.
+     *     app.
+     * @param allowShareAction Whether the view should allow the share action.
      * @return Intent that can be fired to open the file.
      */
     public static Intent getMediaViewerIntent(
-            Uri displayUri,
-            Uri contentUri,
-            String mimeType,
+            @Nullable Uri displayUri,
+            @Nullable Uri contentUri,
+            @Nullable String mimeType,
             boolean allowExternalAppHandlers,
             boolean allowShareAction,
             Context context) {
@@ -138,7 +142,8 @@
         intent.setPackage(context.getPackageName());
         intent.setData(contentUri);
         intent.putExtra(CustomTabIntentDataProvider.EXTRA_UI_TYPE, CustomTabsUiType.MEDIA_VIEWER);
-        intent.putExtra(CustomTabIntentDataProvider.EXTRA_MEDIA_VIEWER_URL, displayUri.toString());
+        intent.putExtra(
+                CustomTabIntentDataProvider.EXTRA_MEDIA_VIEWER_URL, String.valueOf(displayUri));
         intent.putExtra(CustomTabIntentDataProvider.EXTRA_ENABLE_EMBEDDED_MEDIA_EXPERIENCE, true);
         intent.putExtra(CustomTabIntentDataProvider.EXTRA_INITIAL_BACKGROUND_COLOR, mediaColor);
         intent.putExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, mediaColor);
@@ -152,14 +157,18 @@
 
     /**
      * Creates an Intent to open the file in another app by firing an Intent to Android.
-     * @param fileUri  Uri pointing to the file.
+     *
+     * @param fileUri Uri pointing to the file.
      * @param mimeType MIME type for the file.
      * @param originalUrl The original url of the downloaded file.
      * @param referrer Referrer of the downloaded file.
      * @return Intent that can be used to start an Activity for the file.
      */
     public static Intent createViewIntentForUri(
-            Uri fileUri, String mimeType, String originalUrl, String referrer) {
+            @Nullable Uri fileUri,
+            @Nullable String mimeType,
+            @Nullable String originalUrl,
+            @Nullable String referrer) {
         Intent fileIntent = new Intent(Intent.ACTION_VIEW);
         String normalizedMimeType = Intent.normalizeMimeType(mimeType);
         if (TextUtils.isEmpty(normalizedMimeType)) {
@@ -176,12 +185,13 @@
 
     /**
      * Adds the originating Uri and referrer extras to an intent if they are not null.
-     * @param intent      Intent for adding extras.
+     *
+     * @param intent Intent for adding extras.
      * @param originalUrl The original url of the downloaded file.
-     * @param referrer    Referrer of the downloaded file.
+     * @param referrer Referrer of the downloaded file.
      */
     public static void setOriginalUrlAndReferralExtraToIntent(
-            Intent intent, String originalUrl, String referrer) {
+            Intent intent, @Nullable String originalUrl, @Nullable String referrer) {
         if (originalUrl != null) {
             intent.putExtra(Intent.EXTRA_ORIGINATING_URI, Uri.parse(originalUrl));
         }
@@ -194,7 +204,7 @@
      * @param mimeType The MIME type to check.
      * @return MediaLauncherActivity.MediaType enum value for determined media type.
      */
-    static boolean isMediaMIMEType(String mimeType) {
+    static boolean isMediaMIMEType(@Nullable String mimeType) {
         if (TextUtils.isEmpty(mimeType)) return false;
 
         String[] pieces = mimeType.toLowerCase(Locale.getDefault()).split("/");
@@ -279,7 +289,7 @@
                 || !restrictionsManager.getApplicationRestrictions().isEmpty();
     }
 
-    private static Intent createShareIntent(Uri fileUri, String mimeType) {
+    private static Intent createShareIntent(@Nullable Uri fileUri, @Nullable String mimeType) {
         if (TextUtils.isEmpty(mimeType)) mimeType = DEFAULT_MIME_TYPE;
 
         Intent intent = new Intent(Intent.ACTION_SEND);
@@ -290,7 +300,7 @@
         return intent;
     }
 
-    private static boolean isImageType(String mimeType) {
+    private static boolean isImageType(@Nullable String mimeType) {
         if (TextUtils.isEmpty(mimeType)) return false;
 
         String[] pieces = mimeType.toLowerCase(Locale.getDefault()).split("/");
@@ -299,9 +309,9 @@
         return MIMETYPE_IMAGE.equals(pieces[0]);
     }
 
-    private static boolean willExposeFileUri(Uri uri) {
+    private static boolean willExposeFileUri(@Nullable Uri uri) {
         assert uri != null && !uri.equals(Uri.EMPTY) : "URI is not successfully generated.";
-        return uri.getScheme().equals(ContentResolver.SCHEME_FILE);
+        return ContentResolver.SCHEME_FILE.equals(uri.getScheme());
     }
 
     @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java
index 3dff231..b095af19 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureActivity.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.media;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.annotation.SuppressLint;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
@@ -26,8 +28,6 @@
 import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.jni_zero.CalledByNative;
@@ -39,6 +39,9 @@
 import org.chromium.base.UnguessableToken;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.build.annotations.Initializer;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.init.AsyncInitializationActivity;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -59,10 +62,10 @@
 import java.util.HashSet;
 
 /**
- * A picture in picture activity which get created when requesting
- * PiP from web API. The activity will connect to web API through
- * OverlayWindowAndroid.
+ * A picture in picture activity which get created when requesting PiP from web API. The activity
+ * will connect to web API through OverlayWindowAndroid.
  */
+@NullMarked
 public class PictureInPictureActivity extends AsyncInitializationActivity {
     // Used to filter media buttons' remote action intents.
     private static final String MEDIA_ACTION =
@@ -93,21 +96,21 @@
     private static final float MIN_ASPECT_RATIO = 1 / 2.39f;
 
     // The token and corresponding raw pointer to the native side.
-    private UnguessableToken mNativeToken;
+    private @Nullable UnguessableToken mNativeToken;
     private long mNativeOverlayWindowAndroid;
 
     private Tab mInitiatorTab;
-    private InitiatorTabObserver mTabObserver;
+    private @Nullable InitiatorTabObserver mTabObserver;
 
-    private CompositorView mCompositorView;
+    private @Nullable CompositorView mCompositorView;
 
     // If present, this is the video's aspect ratio.
-    private Rational mAspectRatio;
+    private @Nullable Rational mAspectRatio;
 
     // Maximum pip width, in pixels, to prevent resizes that are too big.
     private int mMaxWidth;
 
-    private MediaSessionBroadcastReceiver mMediaSessionReceiver;
+    private @Nullable MediaSessionBroadcastReceiver mMediaSessionReceiver;
 
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     MediaActionButtonsManager mMediaActionsButtonsManager;
@@ -379,7 +382,7 @@
          * @param iconResourceId used for getting icon associated with the id.
          * @param titleResourceId used for getting accessibility title associated with the id.
          * @param controlState indicate the action's state. (e.g. microphone on/off) Null if not
-         * applicable
+         *     applicable
          */
         @SuppressLint("NewApi")
         private RemoteAction createRemoteAction(
@@ -387,7 +390,7 @@
                 int action,
                 int iconResourceId,
                 int titleResourceId,
-                Boolean controlState) {
+                @Nullable Boolean controlState) {
             Intent intent = new Intent(MEDIA_ACTION);
             intent.setPackage(getApplicationContext().getPackageName());
             IntentUtils.addTrustedIntentExtras(intent);
@@ -454,12 +457,16 @@
                     PictureInPictureActivityJni.get().nextSlide(mNativeOverlayWindowAndroid);
                     return;
                 case MediaSessionAction.TOGGLE_MICROPHONE:
+                    // controlState should be non-null if MediaSessionAction toggles control state
                     PictureInPictureActivityJni.get()
-                            .toggleMicrophone(mNativeOverlayWindowAndroid, !controlState);
+                            .toggleMicrophone(
+                                    mNativeOverlayWindowAndroid, !assumeNonNull(controlState));
                     return;
                 case MediaSessionAction.TOGGLE_CAMERA:
+                    // controlState should be non-null if MediaSessionAction toggles control state
                     PictureInPictureActivityJni.get()
-                            .toggleCamera(mNativeOverlayWindowAndroid, !controlState);
+                            .toggleCamera(
+                                    mNativeOverlayWindowAndroid, !assumeNonNull(controlState));
                     return;
                 case MediaSessionAction.HANG_UP:
                     PictureInPictureActivityJni.get().hangUp(mNativeOverlayWindowAndroid);
@@ -499,7 +506,7 @@
     interface LaunchIntoPipHelper {
         // Return a bundle to launch Picture in picture with `bounds` as the source rectangle.
         // May return null if the bundle could not be constructed.
-        Bundle build(Context activityContext, Rect bounds);
+        @Nullable Bundle build(Context activityContext, Rect bounds);
     }
 
     // Default implementation that tries to `makeLaunchIntoPiP` via reflection.  Does nothing,
@@ -507,7 +514,7 @@
     static LaunchIntoPipHelper sLaunchIntoPipHelper =
             new LaunchIntoPipHelper() {
                 @Override
-                public Bundle build(final Context activityContext, final Rect bounds) {
+                public @Nullable Bundle build(final Context activityContext, final Rect bounds) {
                     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return null;
 
                     final Rational aspectRatio = new Rational(bounds.width(), bounds.height());
@@ -530,15 +537,14 @@
         OneshotSupplierImpl<ProfileProvider> supplier = new OneshotSupplierImpl<>();
         ProfileProvider profileProvider =
                 new ProfileProvider() {
-                    @NonNull
+
                     @Override
                     public Profile getOriginalProfile() {
                         return mInitiatorTab.getProfile().getOriginalProfile();
                     }
 
-                    @Nullable
                     @Override
-                    public Profile getOffTheRecordProfile(boolean createIfNeeded) {
+                    public @Nullable Profile getOffTheRecordProfile(boolean createIfNeeded) {
                         if (!mInitiatorTab.getProfile().isOffTheRecord()) {
                             throw new IllegalStateException(
                                     "Attempting to access invalid incognito profile from PiP");
@@ -562,7 +568,7 @@
         // Compute a somewhat arbitrary cut-off of 90% of the window's display width. The PiP
         // window can't be anywhere near this big, so the exact value doesn't matter. We'll ignore
         // resizes messages that are above it, since they're spurious.
-        mMaxWidth = (int) (getWindowAndroid().getDisplay().getDisplayWidth() * 0.95);
+        mMaxWidth = (int) (assumeNonNull(getWindowAndroid()).getDisplay().getDisplayWidth() * 0.95);
 
         mCompositorView =
                 CompositorViewFactory.create(
@@ -615,6 +621,7 @@
 
     @Override
     @SuppressLint("NewAPI") // Picture-in-Picture API will not be enabled for oldver versions.
+    @Initializer
     public void onStart() {
         super.onStart();
 
@@ -627,7 +634,12 @@
             this.finish();
             return;
         }
+        continueInitializationWithNativeToken(intent, mNativeToken);
+    }
 
+    @Initializer
+    private void continueInitializationWithNativeToken(
+            Intent intent, UnguessableToken nativeToken) {
         // Finish the activity if OverlayWindowAndroid has already been destroyed
         // or InitiatorTab has been destroyed by user or crashed.
         mInitiatorTab = TabUtils.fromWebContents(intent.getParcelableExtra(WEB_CONTENTS_KEY));
@@ -635,9 +647,13 @@
             onExitPictureInPicture(/* closeByNative= */ false);
             return;
         }
+        finishInitialize(intent, nativeToken, mInitiatorTab);
+    }
 
+    @Initializer
+    private void finishInitialize(Intent intent, UnguessableToken nativeToken, Tab initiatorTab) {
         mTabObserver = new InitiatorTabObserver();
-        mInitiatorTab.addObserver(mTabObserver);
+        initiatorTab.addObserver(mTabObserver);
 
         mMediaSessionReceiver = new MediaSessionBroadcastReceiver();
         ContextUtils.registerNonExportedBroadcastReceiver(
@@ -647,7 +663,7 @@
 
         mNativeOverlayWindowAndroid =
                 PictureInPictureActivityJni.get()
-                        .onActivityStart(mNativeToken, this, getWindowAndroid());
+                        .onActivityStart(nativeToken, this, getWindowAndroid());
         if (mNativeOverlayWindowAndroid == 0) {
             onExitPictureInPicture(/* closeByNative= */ true);
             return;
@@ -693,6 +709,7 @@
         onExitPictureInPicture(/* closeByNative= */ true);
     }
 
+    @SuppressWarnings("NullAway")
     private void onExitPictureInPicture(boolean closeByNative) {
         if (!closeByNative && mNativeOverlayWindowAndroid != 0) {
             PictureInPictureActivityJni.get().destroyStartedByJava(mNativeOverlayWindowAndroid);
@@ -796,7 +813,7 @@
     }
 
     @VisibleForTesting
-    /* package */ Rational getAspectRatio() {
+    /* package */ @Nullable Rational getAspectRatio() {
         return mAspectRatio;
     }
 
@@ -869,14 +886,16 @@
         return original;
     }
 
-    /* package */ View getViewForTesting() {
-        return mCompositorView.getView();
+    /* package */ @Nullable View getViewForTesting() {
+        return mCompositorView == null ? null : mCompositorView.getView();
     }
 
     @NativeMethods
     public interface Natives {
         long onActivityStart(
-                UnguessableToken token, PictureInPictureActivity self, WindowAndroid window);
+                UnguessableToken token,
+                PictureInPictureActivity self,
+                @Nullable WindowAndroid window);
 
         void destroyStartedByJava(long nativeOverlayWindowAndroid);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterClient.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterClient.java
index fa73794..ccc42e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterClient.java
@@ -15,6 +15,8 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.IntentHandler;
@@ -26,6 +28,7 @@
 import org.chromium.content_public.browser.WebContents;
 
 /** Provides Chrome-specific behavior for Media Router. */
+@NullMarked
 @JNINamespace("media_router")
 public class ChromeMediaRouterClient extends MediaRouterClient {
     private ChromeMediaRouterClient() {}
@@ -63,7 +66,7 @@
     }
 
     @Override
-    public FragmentManager getSupportFragmentManager(WebContents initiator) {
+    public @Nullable FragmentManager getSupportFragmentManager(WebContents initiator) {
         FragmentActivity currentActivity =
                 (FragmentActivity) ApplicationStatus.getLastTrackedFocusedActivity();
         return currentActivity == null ? null : currentActivity.getSupportFragmentManager();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
index 4545cff..323e1b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
@@ -4,12 +4,15 @@
 
 package org.chromium.chrome.browser.media.ui;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Intent;
 import android.graphics.Bitmap;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -19,6 +22,7 @@
 import org.chromium.components.browser_ui.media.MediaNotificationManager;
 import org.chromium.components.browser_ui.media.MediaSessionHelper;
 import org.chromium.components.favicon.LargeIconBridge;
+import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.url.GURL;
 
@@ -26,6 +30,7 @@
  * A tab helper that wraps {@link MediaSessionHelper} and is responsible for Chrome-specific
  * behavior.
  */
+@NullMarked
 public class MediaSessionTabHelper implements MediaSessionHelper.Delegate {
     private @Nullable Tab mTab;
     @VisibleForTesting MediaSessionHelper mMediaSessionHelper;
@@ -40,7 +45,8 @@
                 }
 
                 @Override
-                public void onFaviconUpdated(Tab tab, Bitmap icon, GURL iconUrl) {
+                public void onFaviconUpdated(
+                        Tab tab, @Nullable Bitmap icon, @Nullable GURL iconUrl) {
                     assert tab == mTab;
 
                     if (mMediaSessionHelper == null) return;
@@ -71,10 +77,11 @@
     }
 
     private void maybeCreateOrUpdateMediaSessionHelper() {
+        WebContents webContents = assumeNonNull(assumeNonNull(mTab).getWebContents());
         if (mMediaSessionHelper != null) {
-            mMediaSessionHelper.setWebContents(mTab.getWebContents());
+            mMediaSessionHelper.setWebContents(webContents);
         } else if (mTab.getWebContents() != null) {
-            mMediaSessionHelper = new MediaSessionHelper(mTab.getWebContents(), this);
+            mMediaSessionHelper = new MediaSessionHelper(webContents, this);
         }
     }
 
@@ -89,18 +96,18 @@
     @Override
     public Intent createBringTabToFrontIntent() {
         return IntentHandler.createTrustedBringTabToFrontIntent(
-                mTab.getId(), IntentHandler.BringToFrontSource.NOTIFICATION);
+                assumeNonNull(mTab).getId(), IntentHandler.BringToFrontSource.NOTIFICATION);
     }
 
     @Override
     public LargeIconBridge getLargeIconBridge() {
-        return new LargeIconBridge(mTab.getProfile());
+        return new LargeIconBridge(assumeNonNull(mTab).getProfile());
     }
 
     @Override
     public MediaNotificationInfo.Builder createMediaNotificationInfoBuilder() {
         return new MediaNotificationInfo.Builder()
-                .setInstanceId(mTab.getId())
+                .setInstanceId(assumeNonNull(mTab).getId())
                 .setId(R.id.media_playback_notification);
     }
 
@@ -111,14 +118,14 @@
 
     @Override
     public void hideMediaNotification() {
-        if (mTab == null) return;
+        if (mTab == null) return; // Return early if onDestroy was already called.
 
         MediaNotificationManager.hide(mTab.getId(), R.id.media_playback_notification);
     }
 
     @Override
     public void activateAndroidMediaSession() {
-        if (mTab == null) return;
+        if (mTab == null) return; // Return early if onDestroy was already called.
 
         MediaNotificationManager.activateAndroidMediaSession(
                 mTab.getId(), R.id.media_playback_notification);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerImpl.java
index 53d2dd3..f5300d35 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerImpl.java
@@ -341,6 +341,10 @@
         } else if (id == org.chromium.chrome.R.id.new_window_menu_id) {
             openNewWindow("MobileMenuNewWindow");
             return true;
+        } else if (id == org.chromium.chrome.R.id.new_incognito_window_menu_id) {
+            // TODO(crbug.com/429518328): Hook up with incognito window.
+            openNewWindow("MobileMenuNewIncognitoWindow");
+            return true;
         }
 
         return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 03cd386..d5e7019 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -13,7 +13,6 @@
 import android.text.Editable;
 import android.util.AttributeSet;
 import android.view.DragEvent;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
@@ -89,8 +88,6 @@
     private int mSearchBoxTwoSideMargin;
     private final Context mContext;
 
-    private View mMiddleSpacer; // Spacer between toolbar and Most Likely.
-
     private LogoCoordinator mLogoCoordinator;
     private LogoView mLogoView;
     private SearchBoxCoordinator mSearchBoxCoordinator;
@@ -212,10 +209,9 @@
         // TODO(crbug.com/347509698): Remove the log statements after fixing the bug.
         Log.i(TAG, "NewTabPageLayout.onFinishInflate before insertSiteSectionView");
 
-        mMiddleSpacer = findViewById(R.id.ntp_middle_spacer);
         mFakeSearchBoxLayout = findViewById(R.id.search_box);
         mFakeSearchBoxEditText = findViewById(R.id.search_box_text);
-        insertSiteSectionView();
+        initializeSiteSectionView();
 
         Log.i(TAG, "NewTabPageLayout.onFinishInflate after insertSiteSectionView");
     }
@@ -659,15 +655,10 @@
                 1f);
     }
 
-    private void insertSiteSectionView() {
-        int insertionPoint = indexOfChild(mMiddleSpacer) + 1;
-
+    private void initializeSiteSectionView() {
         mMvTilesContainerLayout =
-                (ViewGroup)
-                        LayoutInflater.from(getContext())
-                                .inflate(R.layout.mv_tiles_container, this, false);
+                (ViewGroup) ((ViewStub) findViewById(R.id.mv_tiles_layout_stub)).inflate();
         mMvTilesContainerLayout.setVisibility(View.VISIBLE);
-        addView(mMvTilesContainerLayout, insertionPoint);
         // The page contents are initially hidden; otherwise they'll be drawn centered on the
         // page before the tiles are available and then jump upwards to make space once the
         // tiles are available.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridge.java
deleted file mode 100644
index 039250b..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridge.java
+++ /dev/null
@@ -1,64 +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.
-
-package org.chromium.chrome.browser.password_manager;
-
-import android.app.Activity;
-
-import androidx.annotation.Nullable;
-
-import org.jni_zero.CalledByNative;
-
-import org.chromium.chrome.browser.LaunchIntentDispatcher;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningHelper;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningType;
-import org.chromium.chrome.browser.access_loss.PwdAccessLossNotificationCoordinator;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
-import org.chromium.ui.base.WindowAndroid;
-
-/**
- * Glue code. Used by C++ to launch the password access loss warning bridge. Allows injecting helper
- * from chrome_java.
- */
-class PasswordAccessLossWarningBridge {
-    PasswordAccessLossWarningHelper mHelper;
-    PwdAccessLossNotificationCoordinator mNotificationCoordinator;
-
-    public PasswordAccessLossWarningBridge(
-            Activity activity, BottomSheetController bottomSheetController, Profile profile) {
-        mHelper =
-                new PasswordAccessLossWarningHelper(
-                        activity,
-                        bottomSheetController,
-                        profile,
-                        LaunchIntentDispatcher::createCustomTabActivityIntent);
-        mNotificationCoordinator =
-                new PwdAccessLossNotificationCoordinator(activity.getBaseContext());
-    }
-
-    @CalledByNative
-    @Nullable
-    static PasswordAccessLossWarningBridge create(WindowAndroid windowAndroid, Profile profile) {
-        BottomSheetController bottomSheetController =
-                BottomSheetControllerProvider.from(windowAndroid);
-        if (bottomSheetController == null) {
-            return null;
-        }
-        Activity activity = windowAndroid.getActivity().get();
-        if (activity == null) {
-            return null;
-        }
-        return new PasswordAccessLossWarningBridge(activity, bottomSheetController, profile);
-    }
-
-    @CalledByNative
-    public void show(@PasswordAccessLossWarningType int warningType) {
-        mHelper.show(warningType);
-    }
-
-    // TODO: crbug.com/354886517 - Introduce the showNotification method and call it from the cpp
-    // bridge.
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
index 3a1c571..9ffd77f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
@@ -32,7 +32,6 @@
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningType;
 import org.chromium.chrome.browser.password_check.PasswordCheck;
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
 import org.chromium.chrome.browser.password_manager.ManagePasswordsReferrer;
@@ -136,7 +135,7 @@
     private final ObservableSupplierImpl<String> mPageTitle = new ObservableSupplierImpl<>();
 
     /** For controlling the UX flow of exporting passwords. */
-    private final ExportFlow mExportFlow = new ExportFlow(PasswordAccessLossWarningType.NONE);
+    private final ExportFlow mExportFlow = new ExportFlow();
 
     public ExportFlow getExportFlowForTesting() {
         return mExportFlow;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesCoordinator.java
index 5fa1e57..80d3af00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesCoordinator.java
@@ -12,7 +12,6 @@
 import android.os.Looper;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
@@ -66,7 +65,6 @@
         mActivity = activity;
         mActivityLifecycleDispatcher = activityLifecycleDispatcher;
 
-        ((ViewStub) mvTilesContainerLayout.findViewById(R.id.mv_tiles_layout_stub)).inflate();
         MostVisitedTilesLayout tilesLayout =
                 mvTilesContainerLayout.findViewById(R.id.mv_tiles_layout);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayout.java
index d4c3e49..98465ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayout.java
@@ -31,13 +31,15 @@
 
     private final boolean mIsTablet;
     private final @Px int mTileViewWidthPx;
+    private final @Px int mIntervalPaddingsTablet;
+    private final @Px int mEdgePaddingsTablet;
+    private final @Px int mTileViewDividerWidth;
     private Integer mInitialTileCount;
     private Integer mInitialChildCount;
-    private final int mIntervalPaddingsTablet;
-    private final int mEdgePaddingsTablet;
     private @Nullable Integer mTileToMoveInViewIdx;
     private @Nullable Runnable mTriggerIphTask;
     private @Nullable SuggestionsTileVerticalDivider mDivider;
+    private @Nullable Integer mDividerIndex;
 
     /** Constructor for inflating from XML. */
     public MostVisitedTilesLayout(Context context, AttributeSet attrs) {
@@ -50,12 +52,32 @@
                 resources.getDimensionPixelSize(R.dimen.tile_view_padding_interval_tablet);
         mEdgePaddingsTablet =
                 resources.getDimensionPixelSize(R.dimen.tile_view_padding_edge_tablet);
+        mTileViewDividerWidth = resources.getDimensionPixelSize(R.dimen.tile_view_divider_width);
     }
 
     @Override
     public void removeAllViews() {
         super.removeAllViews();
         mDivider = null;
+        mDividerIndex = null;
+    }
+
+    @Override
+    void setIntervalMargins(@Px int margin) {
+        super.setIntervalMargins(margin);
+
+        if (mDivider != null) {
+            assert mDividerIndex != null;
+            // Let M = margin, W = divider width, A = adjusted margin. Desired apparent margin that
+            // pretends divider absence is M = A + W + A, so A = (M - W) / 2.
+            @Px int adjustedMargin = (margin - mTileViewDividerWidth) / 2;
+            // Update the start margins of the divider and its next sibling.
+            updateViewStartMargin(mDivider, adjustedMargin);
+            View childAfterDivider = getChildAt(mDividerIndex + 1);
+            if (childAfterDivider != null) {
+                updateViewStartMargin(childAfterDivider, adjustedMargin);
+            }
+        }
     }
 
     @Override
@@ -66,6 +88,7 @@
         // Take the first divider found and assume it's the only one.
         if (view instanceof SuggestionsTileVerticalDivider divider) {
             mDivider = divider;
+            mDividerIndex = getChildCount() - 1;
             mDivider.hide(/* isAnimated= */ false);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TilesLinearLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TilesLinearLayout.java
index ed435b09..7761f3f3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TilesLinearLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TilesLinearLayout.java
@@ -112,7 +112,7 @@
         return ViewUtils.dpToPx(getContext(), mNonTileViewsTotalWidthDp);
     }
 
-    private void updateViewStartMargin(View view, @Px int newStartMargin) {
+    protected void updateViewStartMargin(View view, @Px int newStartMargin) {
         MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
         if (newStartMargin != layoutParams.getMarginStart()) {
             layoutParams.setMarginStart(newStartMargin);
@@ -120,7 +120,7 @@
         }
     }
 
-    private void updateViewEndMargin(View view, @Px int newEndMargin) {
+    protected void updateViewEndMargin(View view, @Px int newEndMargin) {
         MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
         if (newEndMargin != layoutParams.getMarginEnd()) {
             layoutParams.setMarginEnd(newEndMargin);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabArchiver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabArchiver.java
index 2ee88ca..bf0fe30 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabArchiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabArchiver.java
@@ -18,7 +18,7 @@
 
     /** Provides an interface to observer the declutter process. */
     public interface Observer {
-        /** Called when a declutter pass is completeled. */
+        /** Called when a declutter pass is completed. */
         default void onDeclutterPassCompleted() {}
 
         /** Called when the persisted tab data for the archive pass is created. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 97fcb11..2bf60fe4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -588,13 +588,11 @@
 
     @Override
     public int getBackgroundColor() {
-        if (ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()) {
-            if (mCustomView != null && mCustomViewBackgroundColor != null) {
-                return mCustomViewBackgroundColor;
-            }
-            if (mNativePage != null) {
-                return mNativePage.getBackgroundColor();
-            }
+        if (mCustomView != null && mCustomViewBackgroundColor != null) {
+            return mCustomViewBackgroundColor;
+        }
+        if (mNativePage != null) {
+            return mNativePage.getBackgroundColor();
         }
         return mWebContentBackgroundColor;
     }
@@ -1785,8 +1783,7 @@
 
     /** Called to notify when the page had painted something non-empty. */
     void notifyDidFirstVisuallyNonEmptyPaint() {
-        if (ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()
-                && mWaitingOnBgColorAfterHidingNativePage) {
+        if (mWaitingOnBgColorAfterHidingNativePage) {
             onBackgroundColorChanged(
                     BackgroundColorChangeOrigin.BG_COLOR_UPDATE_AFTER_HIDING_NATIVE_PAGE);
         }
@@ -1807,8 +1804,7 @@
 
         int newBackgroundColor = getBackgroundColor();
         // Avoid notifying the observers if the background color hasn't actually changed.
-        if (mTabBackgroundColor == newBackgroundColor
-                && ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()) return;
+        if (mTabBackgroundColor == newBackgroundColor) return;
 
         mTabBackgroundColor = newBackgroundColor;
 
@@ -2067,10 +2063,7 @@
                         mNativePageSmoothTransitionDelegate.prepare();
                     }
                     pushNativePageStateToNavigationEntry();
-
-                    if (ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()) {
-                        onBackgroundColorChanged(BackgroundColorChangeOrigin.NATIVE_PAGE_SHOWN);
-                    }
+                    onBackgroundColorChanged(BackgroundColorChangeOrigin.NATIVE_PAGE_SHOWN);
                     updateThemeColor(TabState.UNSPECIFIED_THEME_COLOR);
                 });
     }
@@ -2733,7 +2726,7 @@
     @NativeMethods
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     public interface Natives {
-        TabImpl fromWebContents(WebContents webContents);
+        TabImpl fromWebContents(@Nullable WebContents webContents);
 
         void init(TabImpl caller, @JniType("Profile*") Profile profile, int id);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
index 8d58e28..1329b393 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUtils.java
@@ -118,7 +118,7 @@
         return screenBounds;
     }
 
-    public static Tab fromWebContents(WebContents webContents) {
+    public static Tab fromWebContents(@Nullable WebContents webContents) {
         return TabImplJni.get().fromWebContents(webContents);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
index 9c9e08c..b652155 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsObserver.java
@@ -32,7 +32,6 @@
 import org.chromium.chrome.browser.bluetooth.BluetoothNotificationManager;
 import org.chromium.chrome.browser.display_cutout.DisplayCutoutTabHelper;
 import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncherImpl;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.media.MediaCaptureNotificationServiceImpl;
 import org.chromium.chrome.browser.pdf.PdfUtils;
 import org.chromium.chrome.browser.policy.PolicyAuditor;
@@ -356,10 +355,8 @@
 
         @Override
         public void onBackgroundColorChanged() {
-            if (ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()) {
-                mTab.changeWebContentBackgroundColor(
-                        assumeNonNull(mTab.getWebContents()).getBackgroundColor());
-            }
+            mTab.changeWebContentBackgroundColor(
+                    assumeNonNull(mTab.getWebContents()).getBackgroundColor());
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
index 0e2671f2..04800a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
@@ -234,6 +234,9 @@
         // New Window
         if (shouldShowNewWindow()) modelList.add(buildNewWindowItem());
 
+        // New Incognito Window
+        if (shouldShowNewIncognitoWindow()) modelList.add(buildNewIncognitoWindowItem());
+
         // Move to other window
         if (shouldShowMoveToOtherWindow()) modelList.add(buildMoveToOtherWindowItem());
 
@@ -537,6 +540,16 @@
                         shouldShowIconBeforeItem() ? R.drawable.ic_new_window : 0));
     }
 
+    private MVCListAdapter.ListItem buildNewIncognitoWindowItem() {
+        assert shouldShowNewIncognitoWindow();
+        return new MVCListAdapter.ListItem(
+                AppMenuHandler.AppMenuItemType.STANDARD,
+                buildModelForStandardMenuItem(
+                        R.id.new_incognito_window_menu_id,
+                        R.string.menu_new_incognito_window,
+                        shouldShowIconBeforeItem() ? R.drawable.ic_incognito : 0));
+    }
+
     private MVCListAdapter.ListItem buildMoveToOtherWindowItem() {
         assert shouldShowMoveToOtherWindow();
         return new MVCListAdapter.ListItem(
@@ -921,6 +934,20 @@
     }
 
     /**
+     * @return Whether the "New incognito window" menu item should be displayed.
+     */
+    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+    public boolean shouldShowNewIncognitoWindow() {
+        // TODO(crbug.com/433789957): A new helper function should be created to consolidate this,
+        // with form factors being checked.
+        if (!ChromeFeatureList.sAndroidOpenIncognitoAsWindow.isEnabled()) {
+            return false;
+        }
+
+        return shouldShowNewWindow();
+    }
+
+    /**
      * @return The number of Chrome instances either running alive or dormant but the state is
      *     present for restoration.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
index b1c61b0..c9cf862 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorController.java
@@ -77,7 +77,7 @@
             color -> updateNavigationBarColor();
     private final Callback<EdgeToEdgeController> mEdgeToEdgeRegisterChangeObserverCallback;
     private EdgeToEdgeSystemBarColorHelper mEdgeToEdgeSystemBarColorHelper;
-    private final @Nullable BottomAttachedUiObserver mBottomAttachedUiObserver;
+    private final BottomAttachedUiObserver mBottomAttachedUiObserver;
     private final TabObserver mTabObserver;
     private final ObserverList<Observer> mObservers = new ObserverList<>();
 
@@ -165,17 +165,15 @@
                 edgeToEdgeControllerSupplier,
                 overviewColorSupplier,
                 edgeToEdgeSystemBarColorHelper,
-                ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()
-                        ? new BottomAttachedUiObserver(
-                                bottomControlsStacker,
-                                browserControlsStateProvider,
-                                snackbarManagerSupplier.get(),
-                                contextualSearchManagerSupplier,
-                                bottomSheetController,
-                                omniboxSuggestionsVisualState,
-                                manualFillingComponentSupplier,
-                                insetObserver)
-                        : null);
+                new BottomAttachedUiObserver(
+                        bottomControlsStacker,
+                        browserControlsStateProvider,
+                        snackbarManagerSupplier.get(),
+                        contextualSearchManagerSupplier,
+                        bottomSheetController,
+                        omniboxSuggestionsVisualState,
+                        manualFillingComponentSupplier,
+                        insetObserver));
     }
 
     @VisibleForTesting
@@ -187,15 +185,13 @@
             ObservableSupplier<EdgeToEdgeController> edgeToEdgeControllerSupplier,
             @NonNull ObservableSupplier<Integer> overviewColorSupplier,
             @NonNull EdgeToEdgeSystemBarColorHelper edgeToEdgeSystemBarColorHelper,
-            @Nullable BottomAttachedUiObserver bottomAttachedUiObserver) {
+            BottomAttachedUiObserver bottomAttachedUiObserver) {
         mContext = context;
         mFullScreenManager = fullscreenManager;
         mEdgeToEdgeSystemBarColorHelper = edgeToEdgeSystemBarColorHelper;
 
         mBottomAttachedUiObserver = bottomAttachedUiObserver;
-        if (mBottomAttachedUiObserver != null) {
-            mBottomAttachedUiObserver.addObserver(this);
-        }
+        mBottomAttachedUiObserver.addObserver(this);
 
         mTabModelSelector = tabModelSelector;
         mTabModelSelectorObserver =
@@ -282,10 +278,9 @@
             mEdgeToEdgeChangeObserver = null;
         }
         mEdgeToEdgeControllerSupplier.removeObserver(mEdgeToEdgeRegisterChangeObserverCallback);
-        if (mBottomAttachedUiObserver != null) {
-            mBottomAttachedUiObserver.removeObserver(this);
-            mBottomAttachedUiObserver.destroy();
-        }
+        mBottomAttachedUiObserver.removeObserver(this);
+        mBottomAttachedUiObserver.destroy();
+
         if (mNavbarColorTransitionAnimation != null) {
             mNavbarColorTransitionAnimation.cancel();
         }
@@ -336,8 +331,7 @@
 
                     @Override
                     public void onFinishedShowing(@LayoutType int layoutType) {
-                        if (ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()
-                                && layoutType == LayoutType.BROWSING) {
+                        if (layoutType == LayoutType.BROWSING) {
                             updateNavigationBarColor();
                         }
                     }
@@ -347,8 +341,6 @@
     }
 
     private void updateActiveTab() {
-        if (!ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()) return;
-
         @Nullable Tab activeTab = mTabModelSelector.getCurrentTab();
         if (activeTab == mActiveTab) return;
 
@@ -503,13 +495,11 @@
     }
 
     private boolean useBottomAttachedUiColor() {
-        return ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()
-                && mBottomAttachedUiColor != null;
+        return mBottomAttachedUiColor != null;
     }
 
     private boolean useActiveTabColor() {
-        return ChromeFeatureList.sNavBarColorMatchesTabBackground.isEnabled()
-                && mLayoutManager != null
+        return mLayoutManager != null
                 && mLayoutManager.getActiveLayoutType() == LayoutType.BROWSING
                 && mActiveTab != null;
     }
diff --git a/chrome/android/javatests/BUILD.gn b/chrome/android/javatests/BUILD.gn
index 40e0bc64..5ca34c8 100644
--- a/chrome/android/javatests/BUILD.gn
+++ b/chrome/android/javatests/BUILD.gn
@@ -150,8 +150,6 @@
     "//chrome/browser/password_manager/android:settings_interface_java",
     "//chrome/browser/password_manager/android:test_support_java",
     "//chrome/browser/password_manager/android:utils_java",
-    "//chrome/browser/password_manager/android/access_loss:enums_java",
-    "//chrome/browser/password_manager/android/access_loss:utils_java",
     "//chrome/browser/password_manager/android/account_storage_toggle:java",
     "//chrome/browser/password_manager/android/pwd_check_wrapper:test_support_java",
     "//chrome/browser/password_manager/android/pwd_migration:java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index a9a6fc1..b9d0a4ca 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -71,7 +71,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.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.NewTabPageTestUtils;
 import org.chromium.components.javascript_dialogs.JavascriptTabModalDialog;
@@ -954,7 +954,7 @@
     @Test
     @MediumTest
     public void testTabIsActivated() {
-        PageStation page0 = mActivityTestRule.startOnBlankPage();
+        CtaPageStation page0 = mActivityTestRule.startOnBlankPage();
 
         TabModel regularModel =
                 mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/metrics/TabbedActivityLaunchCauseMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/metrics/TabbedActivityLaunchCauseMetricsTest.java
index 703a2a7..6dd9fcf4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/metrics/TabbedActivityLaunchCauseMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/metrics/TabbedActivityLaunchCauseMetricsTest.java
@@ -59,7 +59,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.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.util.ChromeApplicationTestUtils;
 import org.chromium.network.mojom.ReferrerPolicy;
 import org.chromium.ui.mojom.WindowOpenDisposition;
@@ -99,7 +99,7 @@
         // If this is the first test in the batch, opens an NTP. Otherwise, opens a blank page.
         mActivityTestRule
                 .startFromLauncherTo()
-                .arriveAt(PageStation.newGenericBuilder().withEntryPoint().build());
+                .arriveAt(CtaPageStation.newGenericBuilder().withEntryPoint().build());
         CriteriaHelper.pollInstrumentationThread(
                 () -> {
                     Criteria.checkThat(
@@ -150,7 +150,7 @@
         // If this is the first test in the batch, opens an NTP. Otherwise, opens a blank page.
         mActivityTestRule
                 .startWithIntentPlusUrlTo(intent, /* url= */ null)
-                .arriveAt(PageStation.newGenericBuilder().withEntryPoint().build());
+                .arriveAt(CtaPageStation.newGenericBuilder().withEntryPoint().build());
         CriteriaHelper.pollInstrumentationThread(
                 () -> {
                     Criteria.checkThat(
@@ -179,7 +179,7 @@
         mActivityTestRule
                 .startWithIntentPlusUrlTo(intent, /* url= */ null)
                 .arriveAt(
-                        PageStation.newGenericBuilder()
+                        CtaPageStation.newGenericBuilder()
                                 .withIncognito(true)
                                 .withEntryPoint()
                                 .build());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragmentTest.java
index 522bac6..de81bfbb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/AutofillCardBenefitsFragmentTest.java
@@ -34,6 +34,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.UserActionTester;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
@@ -94,6 +95,33 @@
                     /* issuerId= */ "amex",
                     /* benefitSource= */ "amex",
                     /* productTermsUrl= */ new GURL("http://www.example.com/amex/terms"));
+    private static final CreditCard SAMPLE_CARD_BMO_WITH_BENEFIT =
+            new CreditCard(
+                    /* guid= */ "",
+                    /* origin= */ "",
+                    /* isLocal= */ false,
+                    /* isVirtual= */ false,
+                    /* name= */ "bmo",
+                    /* number= */ "378282246310005",
+                    /* networkAndLastFourDigits= */ "",
+                    /* month= */ "10",
+                    /* year= */ AutofillTestHelper.nextYear(),
+                    /* basicCardIssuerNetwork= */ "BMO",
+                    /* issuerIconDrawableId= */ R.drawable.visa_metadata_card,
+                    /* billingAddressId= */ "",
+                    /* serverId= */ "",
+                    /* instrumentId= */ 2222,
+                    /* cardLabel= */ "",
+                    /* nickname= */ "",
+                    /* cardArtUrl= */ null,
+                    /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState.UNSPECIFIED,
+                    /* productDescription= */ "eclipse Visa Infinite",
+                    /* cardNameForAutofillDisplay= */ "BMO",
+                    /* obfuscatedLastFourDigits= */ "• • • • 0005",
+                    /* cvc= */ "",
+                    /* issuerId= */ "bmo",
+                    /* benefitSource= */ "bmo",
+                    /* productTermsUrl= */ new GURL("http://www.example.com/bmo/terms"));
     private AutofillTestHelper mAutofillTestHelper;
     private UserActionTester mActionTester;
 
@@ -278,6 +306,54 @@
         assertEquals(3, getPreferenceScreen(activity).getPreferenceCount());
     }
 
+    // Test to verify terms for different card issuers with benefits are listed if the card issuer's
+    // respective benefit feature flag is enabled.
+    @Test
+    @MediumTest
+    public void testCardBenefitsPreferenceScreen_withBenefitFlagsOn() throws Exception {
+        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_AMERICAN_EXPRESS_WITH_BENEFIT);
+        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_BMO_WITH_BENEFIT);
+
+        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
+
+        assertEquals(2, getPreferenceCountWithKey(activity, PREF_KEY_CARD_BENEFIT_TERM));
+    }
+
+    // Test to verify terms for different card issuers with benefits are listed only if the card
+    // issuer's respective benefit feature flag is enabled.
+    @Test
+    @MediumTest
+    @DisableFeatures({ChromeFeatureList.AUTOFILL_ENABLE_CARD_BENEFITS_FOR_BMO})
+    public void testCardBenefitsPreferenceScreen_withOneBenefitFlagOn() throws Exception {
+        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_AMERICAN_EXPRESS_WITH_BENEFIT);
+        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_BMO_WITH_BENEFIT);
+
+        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
+
+        assertEquals(1, getPreferenceCountWithKey(activity, PREF_KEY_CARD_BENEFIT_TERM));
+        assertTrue(
+                doesPreferenceTitleExist(
+                        activity,
+                        SAMPLE_CARD_AMERICAN_EXPRESS_WITH_BENEFIT.getProductDescription()));
+    }
+
+    // Test to verify terms for different card issuers with benefits are not listed if the card
+    // issuer's respective benefit feature flag is disabled.
+    @Test
+    @MediumTest
+    @DisableFeatures({
+        ChromeFeatureList.AUTOFILL_ENABLE_CARD_BENEFITS_FOR_AMERICAN_EXPRESS,
+        ChromeFeatureList.AUTOFILL_ENABLE_CARD_BENEFITS_FOR_BMO
+    })
+    public void testCardBenefitsPreferenceScreen_withBenefitFlagsOff() throws Exception {
+        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_AMERICAN_EXPRESS_WITH_BENEFIT);
+        mAutofillTestHelper.addServerCreditCard(SAMPLE_CARD_BMO_WITH_BENEFIT);
+
+        SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
+
+        assertEquals(0, getPreferenceCountWithKey(activity, PREF_KEY_CARD_BENEFIT_TERM));
+    }
+
     // Test to verify terms for card with the same product (same product description and same
     // issuer) is only displayed once.
     @Test
@@ -370,13 +446,13 @@
                         /* origin= */ "",
                         /* isLocal= */ false,
                         /* isVirtual= */ false,
-                        /* name= */ "capital one",
+                        /* name= */ "bmo",
                         /* number= */ "378282246310001",
                         /* networkAndLastFourDigits= */ "",
                         /* month= */ "10",
                         /* year= */ AutofillTestHelper.nextYear(),
-                        /* basicCardIssuerNetwork= */ "Capital One",
-                        /* issuerIconDrawableId= */ R.drawable.capitalone_metadata_card,
+                        /* basicCardIssuerNetwork= */ "BMO",
+                        /* issuerIconDrawableId= */ R.drawable.visa_metadata_card,
                         /* billingAddressId= */ "",
                         /* serverId= */ "",
                         /* instrumentId= */ 3333,
@@ -386,13 +462,12 @@
                         /* virtualCardEnrollmentState= */ VirtualCardEnrollmentState.UNSPECIFIED,
                         /* productDescription= */ SAMPLE_CARD_AMERICAN_EXPRESS_WITH_BENEFIT
                                 .getProductDescription(),
-                        /* cardNameForAutofillDisplay= */ "Capital One",
+                        /* cardNameForAutofillDisplay= */ "BMO",
                         /* obfuscatedLastFourDigits= */ "• • • • 0001",
                         /* cvc= */ "",
-                        /* issuerId= */ "capitalone",
-                        /* benefitSource= */ "",
-                        /* productTermsUrl= */ new GURL(
-                                "http://www.example.com/capitalone/terms")));
+                        /* issuerId= */ "bmo",
+                        /* benefitSource= */ "bmo",
+                        /* productTermsUrl= */ new GURL("http://www.example.com/bmo/terms")));
 
         SettingsActivity activity = mSettingsActivityTestRule.startSettingsActivity();
 
@@ -438,8 +513,10 @@
     private int getPreferenceCountWithKey(SettingsActivity activity, String preferenceKey) {
         int matchingPreferenceCount = 0;
 
-        for (int i = 0; i < getPreferenceScreen(activity).getPreferenceCount(); i++) {
-            Preference preference = getPreferenceScreen(activity).getPreference(i);
+        for (int preferenceIndex = 0;
+                preferenceIndex < getPreferenceScreen(activity).getPreferenceCount();
+                preferenceIndex++) {
+            Preference preference = getPreferenceScreen(activity).getPreference(preferenceIndex);
             if (preference.getKey() != null && preference.getKey().equals(preferenceKey)) {
                 matchingPreferenceCount++;
             }
@@ -447,6 +524,18 @@
         return matchingPreferenceCount;
     }
 
+    private boolean doesPreferenceTitleExist(SettingsActivity activity, String title) {
+        for (int preferenceIndex = 0;
+                preferenceIndex < getPreferenceScreen(activity).getPreferenceCount();
+                preferenceIndex++) {
+            Preference preference = getPreferenceScreen(activity).getPreference(preferenceIndex);
+            if (preference.getTitle() != null && preference.getTitle().equals(title)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static PreferenceScreen getPreferenceScreen(SettingsActivity activity) {
         return ((AutofillCardBenefitsFragment) activity.getMainFragment()).getPreferenceScreen();
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTabPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTabPTTest.java
index c7902ea6..2bdd010 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTabPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTabPTTest.java
@@ -22,7 +22,7 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule;
 import org.chromium.chrome.test.transit.ChromeTransitTestRules;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabGroupUiFacility;
 import org.chromium.chrome.test.transit.testhtmls.TopBottomLinksPageStation;
@@ -58,7 +58,7 @@
     @Test
     @MediumTest
     public void openNewTabFromContextMenu() {
-        PageStation blankPage = mCtaTestRule.startOnBlankPage();
+        CtaPageStation blankPage = mCtaTestRule.startOnBlankPage();
 
         var topBottomLinkPageAndTop =
                 TopBottomLinksPageStation.loadPage(mCtaTestRule.getActivityTestRule(), blankPage);
@@ -73,7 +73,7 @@
     @Test
     @MediumTest
     public void openNewTabInGroupFromContextMenu() {
-        PageStation blankPage = mCtaTestRule.startOnBlankPage();
+        CtaPageStation blankPage = mCtaTestRule.startOnBlankPage();
 
         var topBottomLinkPageAndTop =
                 TopBottomLinksPageStation.loadPage(mCtaTestRule.getActivityTestRule(), blankPage);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java
index 41e0886b..6113516 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sensitive_content/SensitiveContentTest.java
@@ -85,7 +85,7 @@
 import org.chromium.chrome.test.transit.hub.RegularTabSwitcherStation;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.SwipingToTabFacility;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.util.browser.tabmodel.MockTabModelSelector;
@@ -160,7 +160,7 @@
     public void testTabHasSensitiveContentWhileSensitiveFieldsArePresent() {
         assertNotSensitive(mPage);
 
-        PageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
+        CtaPageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
         assertSensitive(page);
 
         page = page.loadWebPageProgrammatically(mTestServer.getURL(NOT_SENSITIVE_FILE));
@@ -182,7 +182,7 @@
         ThreadUtils.runOnUiThreadBlocking(() -> client.addObserver(observer));
 
         assertFalse(observer.getContentSensitivity());
-        PageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
+        CtaPageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
         assertSensitive(page);
         assertTrue(observer.getContentSensitivity());
 
@@ -234,7 +234,7 @@
         final Tab tab = mCtaTestRule.getActivity().getActivityTab();
         assertFalse(tab.getTabHasSensitiveContent());
 
-        PageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
+        CtaPageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
         assertSensitive(page);
         assertTrue(tab.getTabHasSensitiveContent());
 
@@ -252,7 +252,7 @@
         HistogramWatcher histogramWatcherForTrueBucket =
                 HistogramWatcher.newSingleRecordWatcher(histogram, /* value= */ true);
         // Open a second tab.
-        PageStation page = mPage.openNewTabFast();
+        CtaPageStation page = mPage.openNewTabFast();
         final Tab secondTab = page.loadedTabElement.get();
         // Load sensitive content only into the second tab.
         page = page.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
@@ -292,7 +292,7 @@
         HistogramWatcher histogramWatcherForTrueBucket =
                 HistogramWatcher.newSingleRecordWatcher(histogram, /* value= */ true);
         // Open the first incognito tab.
-        PageStation page = mPage.openNewIncognitoTabFast();
+        CtaPageStation page = mPage.openNewIncognitoTabFast();
         // Open the second incognito tab.
         page = page.openNewIncognitoTabFast();
         final Tab secondIncognitoTab = page.loadedTabElement.get();
@@ -330,7 +330,7 @@
     public void testRegularTabSwitcherBecomesSensitiveWithTabGroups() {
         final Tab firstTab = mPage.loadedTabElement.get();
         // Open a second tab.
-        PageStation page = mPage.openNewTabFast();
+        CtaPageStation page = mPage.openNewTabFast();
         final Tab secondTab = page.loadedTabElement.get();
         // Load sensitive content only into the second tab.
         page = page.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
@@ -354,7 +354,7 @@
     @EnableFeatures(SensitiveContentFeatures.SENSITIVE_CONTENT_WHILE_SWITCHING_TABS)
     public void testIncognitoTabSwitcherBecomesSensitiveWithTabGroups() {
         // Open the first incognito tab.
-        PageStation page = mPage.openNewIncognitoTabFast();
+        CtaPageStation page = mPage.openNewIncognitoTabFast();
         final Tab firstIncognitoTab = page.loadedTabElement.get();
         // Open the second incognito tab.
         page = page.openNewIncognitoTabFast();
@@ -387,7 +387,7 @@
                 HistogramWatcher.newSingleRecordWatcher(histogram, /* value= */ true);
         // Load sensitive content only into the first tab.
         final Tab firstTab = mPage.loadedTabElement.get();
-        PageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
+        CtaPageStation page = mPage.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
         pollUiThread(() -> firstTab.getTabHasSensitiveContent());
         // Open a second tab.
         page = page.openNewTabFast();
@@ -414,7 +414,7 @@
     @LargeTest
     @EnableFeatures(SensitiveContentFeatures.SENSITIVE_CONTENT_WHILE_SWITCHING_TABS)
     public void testSwipingBetweenTabsIsSensitive() {
-        PageStation page = mPage;
+        CtaPageStation page = mPage;
         // Set up.
         // Open a second tab.
         page = page.openNewTabFast();
@@ -480,15 +480,15 @@
         return activity.findViewById(android.R.id.content).getContentSensitivity();
     }
 
-    private void assertNotSensitive(PageStation page) {
+    private void assertNotSensitive(CtaPageStation page) {
         assertNotEquals(View.CONTENT_SENSITIVITY_SENSITIVE, getPageContentSensitivity(page));
     }
 
-    private void assertSensitive(PageStation page) {
+    private void assertSensitive(CtaPageStation page) {
         assertEquals(View.CONTENT_SENSITIVITY_SENSITIVE, getPageContentSensitivity(page));
     }
 
-    private int getPageContentSensitivity(PageStation page) {
+    private int getPageContentSensitivity(CtaPageStation page) {
         return page.loadedTabElement.get().getContentView().getContentSensitivity();
     }
 
@@ -593,7 +593,7 @@
     @EnableFeatures(SensitiveContentFeatures.SENSITIVE_CONTENT_WHILE_SWITCHING_TABS)
     public void testSensitiveContentIsRestoredFromTabState() {
         // Create a new tab.
-        PageStation page = mPage.openNewTabFast();
+        CtaPageStation page = mPage.openNewTabFast();
         final Tab secondTabBeforeFreeze = page.loadedTabElement.get();
         page = page.loadWebPageProgrammatically(mTestServer.getURL(SENSITIVE_FILE));
         pollUiThread(() -> secondTabBeforeFreeze.getTabHasSensitiveContent());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/PermissionInfoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/PermissionInfoTest.java
index e0cc2ed..0635852 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/PermissionInfoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/PermissionInfoTest.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.site_settings;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 
 import androidx.test.filters.SmallTest;
 
@@ -33,8 +32,8 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
+import org.chromium.components.browser_ui.site_settings.GeolocationSetting;
 import org.chromium.components.browser_ui.site_settings.PermissionInfo;
-import org.chromium.components.browser_ui.site_settings.PermissionInfo.GeolocationSetting;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
@@ -281,24 +280,55 @@
     @SmallTest
     @Feature({"Preferences"})
     @EnableFeatures("ApproximateGeolocationPermission")
+    public void testGeolocationSetting() throws Throwable {
+        Profile regularProfile = getRegularProfile();
+        var info =
+                new PermissionInfo(
+                        ContentSettingsType.GEOLOCATION_WITH_OPTIONS,
+                        "https://example.com",
+                        "https://example.com",
+                        false,
+                        SessionModel.DURABLE);
+
+        var defaultSetting =
+                new GeolocationSetting(ContentSettingValues.ASK, ContentSettingValues.ASK);
+        var allowApproximate =
+                new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.BLOCK);
+
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    assertEquals(defaultSetting, info.getGeolocationSetting(regularProfile));
+                    info.setGeolocationSetting(regularProfile, allowApproximate);
+                    assertEquals(allowApproximate, info.getGeolocationSetting(regularProfile));
+                });
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @EnableFeatures("ApproximateGeolocationPermission")
     public void testGeolocationPermissionMockValues() throws Throwable {
         PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_SAMPLE_DATA.setForTesting(true);
         Profile regularProfile = getRegularProfile();
-        var permissionSiteInfo =
+        var info =
                 new PermissionInfo(
-                        ContentSettingsType.GEOLOCATION,
+                        ContentSettingsType.GEOLOCATION_WITH_OPTIONS,
                         "https://permission.site",
                         "https://permission.site",
                         false,
                         SessionModel.DURABLE);
-        assertEquals(
-                new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.BLOCK),
-                permissionSiteInfo.getGeolocationSetting(regularProfile));
 
-        GeolocationSetting allow_precise =
+        var allowApproximate =
+                new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.BLOCK);
+        var allowPrecise =
                 new GeolocationSetting(ContentSettingValues.ALLOW, ContentSettingValues.ALLOW);
-        permissionSiteInfo.setGeolocationSetting(regularProfile, allow_precise);
-        assertEquals(allow_precise, permissionSiteInfo.getGeolocationSetting(regularProfile));
+
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    assertEquals(allowApproximate, info.getGeolocationSetting(regularProfile));
+                    info.setGeolocationSetting(regularProfile, allowPrecise);
+                    assertEquals(allowPrecise, info.getGeolocationSetting(regularProfile));
+                });
     }
 
     @Test
@@ -308,13 +338,18 @@
     public void testGeolocationPermissionDefault() throws Throwable {
         PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_SAMPLE_DATA.setForTesting(false);
         Profile regularProfile = getRegularProfile();
-        var permissionSiteInfo =
+        var info =
                 new PermissionInfo(
-                        ContentSettingsType.GEOLOCATION,
+                        ContentSettingsType.GEOLOCATION_WITH_OPTIONS,
                         "https://permission.site",
                         "https://permission.site",
                         false,
                         SessionModel.DURABLE);
-        assertNull(permissionSiteInfo.getGeolocationSetting(regularProfile));
+
+        var defaultSetting =
+                new GeolocationSetting(ContentSettingValues.ASK, ContentSettingValues.ASK);
+
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> assertEquals(defaultSetting, info.getGeolocationSetting(regularProfile)));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
index 06ddb00..b3ea450 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/WebsitePermissionsFetcherTest.java
@@ -722,7 +722,7 @@
         // Otherwise, just update count in the assert.
         // TODO(https://b/332704817): Add test for Tracking Protection content setting after Android
         // integration.
-        assertEquals(122, ContentSettingsType.MAX_VALUE);
+        assertEquals(123, ContentSettingsType.MAX_VALUE);
         websitePreferenceBridge.addContentSettingException(
                 new ContentSettingException(
                         ContentSettingsType.COOKIES,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
index 84ea7763..35daf35 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
@@ -304,10 +304,7 @@
                     ViewGroup containerLayout =
                             (ViewGroup)
                                     LayoutInflater.from(contentView.getContext())
-                                            .inflate(
-                                                    R.layout.mv_tiles_container,
-                                                    contentView,
-                                                    false);
+                                            .inflate(R.layout.mv_tiles_layout, contentView, false);
                     containerLayout.setVisibility(View.VISIBLE);
                     contentView.addView(containerLayout);
                     initializeCoordinator(containerLayout);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java
index 719c577..dc649156 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuBatchedPTTest.java
@@ -31,7 +31,7 @@
 import org.chromium.chrome.test.transit.hub.RegularTabSwitcherStation;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.TabSwitcherActionMenuFacility;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -143,7 +143,7 @@
     public void testSwitchIntoAndOutOfIncognito() {
         // Open 1 regular and 1 incognito tab.
         WebPageStation blankPage = mCtaTestRule.start();
-        PageStation incognitoNtp = blankPage.openNewIncognitoTabFast();
+        CtaPageStation incognitoNtp = blankPage.openNewIncognitoTabFast();
 
         // Open action menu and switch out of incognito.
         TabSwitcherActionMenuFacility actionMenu = incognitoNtp.openTabSwitcherActionMenu();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java
index 148f061..7e01c389 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuPTTest.java
@@ -29,7 +29,7 @@
 import org.chromium.chrome.test.transit.hub.RegularTabSwitcherStation;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.TabSwitcherActionMenuFacility;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 
@@ -123,8 +123,8 @@
     @LargeTest
     public void testSwitchIntoAndOutOfIncognito() {
         // Open 1 regular and 1 incognito tab.
-        PageStation blankPage = mCtaTestRule.startOnBlankPage();
-        PageStation incognitoNtp = blankPage.openNewIncognitoTabFast();
+        CtaPageStation blankPage = mCtaTestRule.startOnBlankPage();
+        CtaPageStation incognitoNtp = blankPage.openNewIncognitoTabFast();
 
         // Open action menu and switch out of incognito.
         TabSwitcherActionMenuFacility actionMenu = incognitoNtp.openTabSwitcherActionMenu();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/OWNERS
index 147d604..db55bc9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/OWNERS
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/OWNERS
@@ -1,5 +1 @@
 file://chrome/android/java/src/org/chromium/chrome/browser/autofill/OWNERS
-
-# Payments-relevant files
-per-file AutofillImageFetcher*Test.java=file://components/autofill/core/browser/payments/ANDROID_OWNERS
-per-file AutofillUiUtilsTest.java=file://components/autofill/core/browser/payments/ANDROID_OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridgeTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridgeTest.java
deleted file mode 100644
index 11e2a966..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordAccessLossWarningBridgeTest.java
+++ /dev/null
@@ -1,73 +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.
-
-package org.chromium.chrome.browser.password_manager;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.content.Context;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
-
-/** Tests for {@link PasswordAccessLossWarningBridge} */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-@Batch(Batch.PER_CLASS)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PasswordAccessLossWarningBridgeTest {
-    private PasswordAccessLossWarningBridge mBridge;
-    private final ArgumentCaptor<BottomSheetObserver> mBottomSheetObserverCaptor =
-            ArgumentCaptor.forClass(BottomSheetObserver.class);
-    private Context mContext;
-
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
-    @Mock private BottomSheetController mBottomSheetController;
-    @Mock private Profile mProfile;
-    @Mock private Activity mActivity;
-
-    @Before
-    public void setUp() {
-        mContext = ContextUtils.getApplicationContext();
-
-        mBridge =
-                new PasswordAccessLossWarningBridge(
-                        mContext, mBottomSheetController, mProfile, mActivity);
-    }
-
-    private void setUpBottomSheetController() {
-        when(mBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
-        doNothing().when(mBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture());
-    }
-
-    @Test
-    public void showsSheet() {
-        setUpBottomSheetController();
-        mBridge.show(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED);
-        verify(mBottomSheetController).requestShowContent(any(), anyBoolean());
-        verify(mBottomSheetController).addObserver(any());
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
index eba81a3..d0099167 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
@@ -54,7 +54,6 @@
 import java.util.Optional;
 
 @RunWith(BaseRobolectricTestRunner.class)
-// TODO(crbug.com/425761643): Re-enable after nav bar color animations finch experiment.
 @DisableFeatures(ChromeFeatureList.NAV_BAR_COLOR_ANIMATION)
 public class BottomAttachedUiObserverTest {
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
index 095789e..1f4327e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -1513,6 +1513,7 @@
     }
 
     @Test
+    @DisableFeatures(ChromeFeatureList.ANDROID_OPEN_INCOGNITO_AS_WINDOW)
     public void testShouldShowNewMenu_isTabletSizedScreen_returnsTrue() {
         assertTrue(
                 doTestShouldShowNewMenu(
@@ -1525,6 +1526,25 @@
                         /* isInMultiWindowMode= */ false,
                         /* isInMultiDisplayMode= */ false,
                         /* isMultiInstanceRunning= */ false));
+        assertFalse(mTabbedAppMenuPropertiesDelegate.shouldShowNewIncognitoWindow());
+        verify(mTabbedAppMenuPropertiesDelegate, atLeastOnce()).isTabletSizeScreen();
+    }
+
+    @Test
+    @EnableFeatures(ChromeFeatureList.ANDROID_OPEN_INCOGNITO_AS_WINDOW)
+    public void testShouldShowNewMenu_isTabletSizedScreen_returnsTrue_withNewIncognitoWindow() {
+        assertTrue(
+                doTestShouldShowNewMenu(
+                        /* isAutomotive= */ false,
+                        /* isInstanceSwitcherEnabled= */ true,
+                        /* currentWindowInstances= */ 1,
+                        /* isTabletSizeScreen= */ true,
+                        /* canEnterMultiWindowMode= */ false,
+                        /* isChromeRunningInAdjacentWindow= */ false,
+                        /* isInMultiWindowMode= */ false,
+                        /* isInMultiDisplayMode= */ false,
+                        /* isMultiInstanceRunning= */ false));
+        assertTrue(mTabbedAppMenuPropertiesDelegate.shouldShowNewIncognitoWindow());
         verify(mTabbedAppMenuPropertiesDelegate, atLeastOnce()).isTabletSizeScreen();
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorControllerUnitTest.java
index bb1dc4b..dcca8391 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorControllerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedNavigationBarColorControllerUnitTest.java
@@ -63,8 +63,6 @@
         manifest = Config.NONE,
         shadows = {TabbedNavigationBarColorControllerUnitTest.ShadowSemanticColorUtils.class},
         sdk = 29)
-@EnableFeatures(ChromeFeatureList.NAV_BAR_COLOR_MATCHES_TAB_BACKGROUND)
-// TODO(crbug.com/425761643): Re-enable after nav bar color animations finch experiment.
 @DisableFeatures(ChromeFeatureList.NAV_BAR_COLOR_ANIMATION)
 public class TabbedNavigationBarColorControllerUnitTest {
     public @Rule MockitoRule mockitoRule = MockitoJUnit.rule();
diff --git a/chrome/android/modules/on_demand/java/src/org/chromium/chrome/browser/data_import/DataImporterServiceImpl.java b/chrome/android/modules/on_demand/java/src/org/chromium/chrome/browser/data_import/DataImporterServiceImpl.java
index 225dd31..f176106 100644
--- a/chrome/android/modules/on_demand/java/src/org/chromium/chrome/browser/data_import/DataImporterServiceImpl.java
+++ b/chrome/android/modules/on_demand/java/src/org/chromium/chrome/browser/data_import/DataImporterServiceImpl.java
@@ -7,15 +7,22 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.util.Base64;
 
+import io.grpc.Context;
+import io.grpc.Contexts;
+import io.grpc.Metadata;
 import io.grpc.Server;
+import io.grpc.ServerInterceptor;
+import io.grpc.ServerInterceptors;
 import io.grpc.Status;
 import io.grpc.StatusRuntimeException;
 import io.grpc.binder.AndroidComponentAddress;
 import io.grpc.binder.BinderServerBuilder;
 import io.grpc.binder.IBinderReceiver;
 import io.grpc.binder.InboundParcelablePolicy;
+import io.grpc.binder.ParcelableUtils;
 import io.grpc.binder.SecurityPolicies;
 import io.grpc.binder.SecurityPolicy;
 import io.grpc.binder.ServerSecurityPolicy;
@@ -50,7 +57,9 @@
         mServer =
                 BinderServerBuilder.forAddress(
                                 AndroidComponentAddress.forContext(getService()), mBinderReceiver)
-                        .addService(new TargetService())
+                        .addService(
+                                ServerInterceptors.intercept(
+                                        new TargetService(), new ParcelableMetadataInterceptor()))
                         .securityPolicy(getServerSecurityPolicy())
                         .inboundParcelablePolicy(getInboundParcelablePolicy())
                         .build();
@@ -127,6 +136,30 @@
         return InboundParcelablePolicy.newBuilder().setAcceptParcelableMetadataValues(true).build();
     }
 
+    // Key under which the ParcelFileDescriptor (aka input file) is stored in the request metadata
+    // and, after the interceptor has copied it, in the grpc context.
+    static final String PFD_KEY = "pfd-keys-bin";
+    static final Context.Key<ParcelFileDescriptor> PFD_CONTEXT_KEY = Context.key(PFD_KEY);
+
+    // Helper class which copies the ParcelFileDescriptor (input file) from request metadata into
+    // the grpc context, where individual RPC implementations can access it.
+    static class ParcelableMetadataInterceptor implements ServerInterceptor {
+        static final Metadata.Key<ParcelFileDescriptor> PFD_METADATA_KEY =
+                ParcelableUtils.metadataKey(PFD_KEY, ParcelFileDescriptor.CREATOR);
+
+        @Override
+        public <ReqT, RespT> io.grpc.ServerCall.Listener<ReqT> interceptCall(
+                io.grpc.ServerCall<ReqT, RespT> call,
+                io.grpc.Metadata headers,
+                io.grpc.ServerCallHandler<ReqT, RespT> next) {
+            Context context = Context.current();
+            if (headers.containsKey(PFD_METADATA_KEY)) {
+                context = context.withValue(PFD_CONTEXT_KEY, headers.get(PFD_METADATA_KEY));
+            }
+            return Contexts.interceptCall(context, call, headers, next);
+        }
+    }
+
     static class TargetService extends TargetServiceGrpc.TargetServiceImplBase {
         @Override
         public void handshake(
@@ -165,7 +198,14 @@
                     return;
             }
 
-            // TODO(crbug.com/431218724): Parse the file descriptor out of the request metadata.
+            ParcelFileDescriptor pfd = PFD_CONTEXT_KEY.get(Context.current());
+            if (pfd == null) {
+                responseObserver.onError(
+                        new StatusRuntimeException(
+                                Status.INVALID_ARGUMENT.withDescription(
+                                        "Missing ParcelFileDescriptor")));
+                return;
+            }
 
             BrowserFileType fileType;
             try {
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 8e268101..1d79085f 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-140.0.7309.0_pre1489350_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-140.0.7314.0_pre1490791_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 55e7184..53fb7254 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-140.0.7309.0_pre1489350_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-140.0.7313.0_pre1490386_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 7405ae15..b914bbc 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8511,8 +8511,8 @@
       <message name="IDS_NTP_COMPOSE_IMAGE_UPLOAD_BUTTON_A11Y_LABEL" desc="The accessibility label for the image upload button on the compose box.">
         Upload an image
       </message>
-      <message name="IDS_NTP_COMPOSE_FILE_UPLOAD_BUTTON_A11Y_LABEL" desc="The accessibility label for the file upload button on the compose box.">
-        Upload a file
+      <message name="IDS_NTP_COMPOSE_PDF_UPLOAD_BUTTON_A11Y_LABEL" desc="The accessibility label for the file upload button on the compose box." translateable="false">
+        Upload a PDF
       </message>
       <message name="IDS_NTP_COMPOSE_SUBMIT_BUTTON_A11Y_LABEL" desc="The accessibility label for the submit button on the compose box.">
         Send
diff --git a/chrome/app/generated_resources_grd/IDS_NTP_COMPOSE_FILE_UPLOAD_BUTTON_A11Y_LABEL.png.sha1 b/chrome/app/generated_resources_grd/IDS_NTP_COMPOSE_FILE_UPLOAD_BUTTON_A11Y_LABEL.png.sha1
deleted file mode 100644
index a069896..0000000
--- a/chrome/app/generated_resources_grd/IDS_NTP_COMPOSE_FILE_UPLOAD_BUTTON_A11Y_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7bab8f89d2e206101c78515473cffa05cecc6764
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 031fc92..d56fa07 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -867,6 +867,13 @@
   <message name="IDS_SETTINGS_MANAGE_IN_YOUR_GOOGLE_ACCOUNT" desc="Description for the MyActivity and Search History linkouts in the 'Other Google Data' subpage inside the 'Delete browsing data' dialog. This lets users know that this data can be managed and deleted in their Google account.">
     Manage in your Google Account
   </message>
+  <message name="IDS_SETTINGS_MANAGE_IN_YOUR_GEMINI_APPS_ACTIVITY" desc="Description for the Gemini Apps Activity linkout.">
+    Manage your Gemini Apps activity
+</message>
+<message name="IDS_SETTINGS_GEMINI_APPS_ACTIVITY" desc="Title for the Gemini Apps Activity section in Other Data.">
+    Gemini Apps activity
+</message>
+
   <message name="IDS_SETTINGS_PASSWORDS_AND_PASSKEYS" desc="Label for the 'Passwords and Passkeys' linkout in the 'Other Google Data' subpage inside the 'Delete browsing data' dialog, where the user can see and manage data that is stored outside of Chrome. This linkout is specifically for passwords and passkeys stored in Google password manager.">
     Passwords and passkeys
   </message>
@@ -4438,14 +4445,14 @@
   </message>
 
     <!-- Experimental settings - Password Change -->
-  <message name="IDS_SETTINGS_PASSWORD_CHANGE_LABEL" desc="Primary label for password change entry in settings.">
+  <message name="IDS_SETTINGS_PASSWORD_CHANGE_LABEL" desc="Primary label for password change entry in settings. The user is in settings and this string represents the name of the feature. We were careful to choose “automated” and not “automatic” because we don’t want to give the user the impression that this will happen without their knowledge. There is an ‘automated’ process that the user initiates, but the process isn’t ‘automatic’ in the sense that it might be happening behind the scenes without the user’s knowledge.">
     Automated Password Change
   </message>
-  <message name="IDS_SETTINGS_PASSWORD_CHANGE_SUBLABEL" desc="Sublabel for password change entry in settings.">
-    When Chrome finds one of your passwords in a data breach, it can offer to change your password for you when you sign in
+  <message name="IDS_SETTINGS_PASSWORD_CHANGE_SUBLABEL" desc="Sublabel for password change entry in settings. The description of the feature beneath the “Automated password change” feature title. This and the bullets beneath this paragraph represent the full description of the feature. * “public” does two things: 1) it provides distance between “Chrome” and “data breach”, because we don’t want users to associate the breach with Chrome (Chrome didn’t have a data leak, 2) and related, it might reassure the user to know that Chrome is using public information to establish these lists of compromised passwords. * “Google Password Manager can offer…”: The user has to agree to have this feature update their password for them each time. So Google Password Manager is ‘offering’ to do something for the user.">
+    If Chrome finds one of your passwords in a data breach, Google Password Manager can offer to change your password for you if you're signed in.
   </message>
-  <message name="IDS_SETTINGS_PASSWORD_CHANGE_DATA_BREACH" desc="One of the bullet points explaining what happens when the feature is used.">
-    When one of your passwords is found in a data breach, Google Password Manager asks if you want it changed to a strong password
+  <message name="IDS_SETTINGS_PASSWORD_CHANGE_DATA_BREACH" desc="Bullet 1 of 2 that appears beneath the “When used” subtitle. This string is repetitive of the feature description, but we want to have a complete description of what happens when the feature is used. * “Google Password Manager asks…”: This part is similar to the general feature description above, but it’s written as if the feature is being used by the user, so we use “asks” and not “can offer”. * “Strong password”: As an existing autofill feature, Google Password Manager can offer to generate and save passwords for the user. These passwords are typically stronger than passwords the user might create on their own">
+    If one of your passwords is found in a data breach, Google Password Manager asks if you want it changed to a strong password
   </message>
   <message name="IDS_SETTINGS_PASSWORD_CHANGE_WHERE_SAVED" desc="One of the bullet points explaining what happens when the feature is used.">
     You don't need to remember the password because it gets saved for you in Google Password Manager
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_GEMINI_APPS_ACTIVITY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GEMINI_APPS_ACTIVITY.png.sha1
new file mode 100644
index 0000000..71e9d95
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_GEMINI_APPS_ACTIVITY.png.sha1
@@ -0,0 +1 @@
+0fc5dc204b69c93799c81285fcec4ef35ad2f0e5
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_IN_YOUR_GEMINI_APPS_ACTIVITY.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_IN_YOUR_GEMINI_APPS_ACTIVITY.png.sha1
new file mode 100644
index 0000000..c66ac26
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_MANAGE_IN_YOUR_GEMINI_APPS_ACTIVITY.png.sha1
@@ -0,0 +1 @@
+511db9426c11717f897af590c4777e086146077c
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_DATA_BREACH.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_DATA_BREACH.png.sha1
index 57f0a8f..f44777c 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_DATA_BREACH.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_DATA_BREACH.png.sha1
@@ -1 +1 @@
-ae544c85bbcd8ca7c445bbbbe99f1cdab9d4686e
\ No newline at end of file
+b110b335a81a3f2854d3df511832829cac407c2d
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_LABEL.png.sha1
index 78f16d9..f44777c 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_LABEL.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_LABEL.png.sha1
@@ -1 +1 @@
-86e57c6658981af5aed186e7cc63ad12cf6c85a4
\ No newline at end of file
+b110b335a81a3f2854d3df511832829cac407c2d
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_SUBLABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_SUBLABEL.png.sha1
index e2a4ba8..f44777c 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_SUBLABEL.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_PASSWORD_CHANGE_SUBLABEL.png.sha1
@@ -1 +1 @@
-dc1472f951e6267ae6a8da13ab2b5a14f5eeccc3
\ No newline at end of file
+b110b335a81a3f2854d3df511832829cac407c2d
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index eb9c64fa..39788f94 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3207,8 +3207,6 @@
       "password_manager/android/generated_password_saved_message_delegate.h",
       "password_manager/android/local_passwords_migration_warning_util.cc",
       "password_manager/android/local_passwords_migration_warning_util.h",
-      "password_manager/android/password_access_loss_warning_startup_launcher.cc",
-      "password_manager/android/password_access_loss_warning_startup_launcher.h",
       "password_manager/android/password_accessory_metrics_util.h",
       "password_manager/android/password_checkup_launcher_helper.cc",
       "password_manager/android/password_checkup_launcher_helper.h",
@@ -4034,6 +4032,8 @@
       "new_tab_page/modules/v2/calendar/outlook_calendar_page_handler.h",
       "new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption_page_handler.cc",
       "new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption_page_handler.h",
+      "new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc",
+      "new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h",
       "new_tab_page/new_tab_page_util.cc",
       "new_tab_page/new_tab_page_util.h",
       "new_tab_page/one_google_bar/one_google_bar_data.cc",
@@ -8689,6 +8689,7 @@
       "//chrome/browser/new_tab_page/modules/v2/authentication:mojo_bindings",
       "//chrome/browser/new_tab_page/modules/v2/calendar:mojo_bindings",
       "//chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption:mojo_bindings",
+      "//chrome/browser/new_tab_page/modules/v2/tab_groups:mojo_bindings",
       "//chrome/browser/profile_resetter:profile_reset_report_proto",
       "//chrome/browser/share/proto:proto",
       "//chrome/browser/support_tool:support_tool_proto",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index aaee64e..66ae99f9 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2430,6 +2430,14 @@
     {"- Combined Suggestions", kNtpSharepointModuleCombinedSuggestions,
      std::size(kNtpSharepointModuleCombinedSuggestions), nullptr}};
 
+const FeatureEntry::FeatureParam kNtpTabGroupsModuleFakeData[] = {
+    {ntp_features::kNtpTabGroupsModuleDataParam, "Fake Data"}};
+
+const FeatureEntry::FeatureVariation kNtpTabGroupsModuleVariations[] = {
+    {"- Fake Data", kNtpTabGroupsModuleFakeData,
+     std::size(kNtpTabGroupsModuleFakeData), nullptr},
+};
+
 const FeatureEntry::FeatureParam kNtpMostRelevantTabResumptionModuleFakeData[] =
     {{ntp_features::kNtpMostRelevantTabResumptionModuleDataParam, "Fake Data"}};
 const FeatureEntry::FeatureParam
@@ -4567,6 +4575,15 @@
          std::size(kGlicPanelResetOnSessionTimeout_24h), nullptr},
         {"Reset after 48h", kGlicPanelResetOnSessionTimeout_48h,
          std::size(kGlicPanelResetOnSessionTimeout_48h), nullptr}};
+
+// Variations on pre-warming delays.
+const FeatureEntry::FeatureParam kGlicWarmingShorterDelays[] = {
+    {"glic-warming-delay-ms", "5000"},
+    {"glic-panel-reset-delay-ms", "2000"}};
+
+const FeatureEntry::FeatureVariation kGlicWarmingVariations[] = {
+    {"with shorter delays", kGlicWarmingShorterDelays,
+     std::size(kGlicWarmingShorterDelays), nullptr}};
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
 const FeatureEntry::FeatureParam kAutofillShowTypePredictionsAsTitle[] = {
@@ -7487,7 +7504,9 @@
 
     {"ntp-tab-groups-module", flag_descriptions::kNtpTabGroupsModuleName,
      flag_descriptions::kNtpTabGroupsModuleDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(ntp_features::kNtpTabGroupsModule)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(ntp_features::kNtpTabGroupsModule,
+                                    kNtpTabGroupsModuleVariations,
+                                    "DesktopNtpModules")},
 
     {"ntp-wallpaper-search-button",
      flag_descriptions::kNtpWallpaperSearchButtonName,
@@ -7661,11 +7680,6 @@
 #endif
 
 #if BUILDFLAG(IS_ANDROID)
-    {"enable-nav-bar-matches-tab-android",
-     flag_descriptions::kNavBarColorMatchesTabBackgroundName,
-     flag_descriptions::kNavBarColorMatchesTabBackgroundDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kNavBarColorMatchesTabBackground)},
-
     {"enable-navigation-capture-refactor-android",
      flag_descriptions::kNavigationCaptureRefactorAndroidName,
      flag_descriptions::kNavigationCaptureRefactorAndroidDescription,
@@ -7868,6 +7882,11 @@
      flag_descriptions::kEnableHeadlessLiveCaptionDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(media::kHeadlessLiveCaption)},
 
+    {"enable-media-link-helpers",
+     flag_descriptions::kEnableMediaLinkHelpersName,
+     flag_descriptions::kEnableMediaLinkHelpersDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(media::kMediaLinkHelpers)},
+
 #if BUILDFLAG(IS_CHROMEOS)
     {"enable-chromeos-live-translate",
      flag_descriptions::kEnableCrOSLiveTranslateName,
@@ -11197,14 +11216,18 @@
      flag_descriptions::kWriterAPIForGeminiNanoName,
      flag_descriptions::kWriterAPIForGeminiNanoDescription,
      kOsMac | kOsWin | kOsLinux,
-     FEATURE_VALUE_TYPE(blink::features::kAIWriterAPI),
+     FEATURE_WITH_PARAMS_VALUE_TYPE(blink::features::kAIWriterAPI,
+                                    kAILangsVariation,
+                                    "kAIWriterAPI"),
      flag_descriptions::kAIAPIsForGeminiNanoLinks},
 
     {"rewriter-api-for-gemini-nano",
      flag_descriptions::kRewriterAPIForGeminiNanoName,
      flag_descriptions::kRewriterAPIForGeminiNanoDescription,
      kOsMac | kOsWin | kOsLinux,
-     FEATURE_VALUE_TYPE(blink::features::kAIRewriterAPI),
+     FEATURE_WITH_PARAMS_VALUE_TYPE(blink::features::kAIRewriterAPI,
+                                    kAILangsVariation,
+                                    "kAIRewriterAPI"),
      flag_descriptions::kAIAPIsForGeminiNanoLinks},
 
     {"proofreader-api-for-gemini-nano",
@@ -11808,6 +11831,14 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(features::kGlicPanelResetOnSessionTimeout,
                                     kGlicPanelResetOnSessionTimeoutVariations,
                                     "GlicPanelResetOnSessionTimeout")},
+    {"glic-pre-warming", flag_descriptions::kGlicWarmingName,
+     flag_descriptions::kGlicWarmingDescription, kOsMac | kOsWin | kOsLinux,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(features::kGlicWarming,
+                                    kGlicWarmingVariations,
+                                    "GlicWarming")},
+    {"glic-fre-pre-warming", flag_descriptions::kGlicFreWarmingName,
+     flag_descriptions::kGlicFreWarmingDescription, kOsMac | kOsWin | kOsLinux,
+     FEATURE_VALUE_TYPE(features::kGlicFreWarming)},
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/actor/actor_keyed_service.cc b/chrome/browser/actor/actor_keyed_service.cc
index 89849d2..7f8ce25 100644
--- a/chrome/browser/actor/actor_keyed_service.cc
+++ b/chrome/browser/actor/actor_keyed_service.cc
@@ -57,6 +57,8 @@
   last_created_task_id_ = task_id;
   task->SetId(base::PassKey<ActorKeyedService>(), task_id);
   task->GetExecutionEngine()->SetOwner(task.get());
+  // Notify of task creation now that the task id is set.
+  NotifyTaskStateChanged(*task);
   active_tasks_[task_id] = std::move(task);
   return task_id;
 }
@@ -115,6 +117,15 @@
   return AddActiveTask(std::move(actor_task));
 }
 
+base::CallbackListSubscription ActorKeyedService::AddTaskStateChangedCallback(
+    TaskStateChangedCallback callback) {
+  return tab_state_change_callback_list_.Add(std::move(callback));
+}
+
+void ActorKeyedService::NotifyTaskStateChanged(const ActorTask& task) {
+  tab_state_change_callback_list_.Notify(task);
+}
+
 void ActorKeyedService::RequestTabObservation(
     const tabs::TabInterface& tab,
     base::OnceCallback<void(TabObservationResult)> callback) {
diff --git a/chrome/browser/actor/actor_keyed_service.h b/chrome/browser/actor/actor_keyed_service.h
index 97282fae..62ee5102 100644
--- a/chrome/browser/actor/actor_keyed_service.h
+++ b/chrome/browser/actor/actor_keyed_service.h
@@ -116,6 +116,13 @@
       const tabs::TabInterface& tab,
       base::OnceCallback<void(TabObservationResult)> callback);
 
+  using TaskStateChangedCallback =
+      base::RepeatingCallback<void(const ActorTask&)>;
+  base::CallbackListSubscription AddTaskStateChangedCallback(
+      TaskStateChangedCallback callback);
+
+  void NotifyTaskStateChanged(const ActorTask& task);
+
  private:
   // Called when the actor coordinator has finished an action which required
   // task creation.
@@ -156,6 +163,9 @@
 
   AggregatedJournal journal_;
 
+  base::RepeatingCallbackList<void(const ActorTask&)>
+      tab_state_change_callback_list_;
+
   // TODO(crbug.com/411462297): Remove
   TaskId last_created_task_id_;
 
diff --git a/chrome/browser/actor/actor_task.cc b/chrome/browser/actor/actor_task.cc
index 3ac2227..483d419 100644
--- a/chrome/browser/actor/actor_task.cc
+++ b/chrome/browser/actor/actor_task.cc
@@ -70,6 +70,7 @@
       ui::UiEventDispatcher::ChangeTaskState{
           .task_id = id_, .old_state = state_, .new_state = state});
   state_ = state;
+  actor::ActorKeyedService::Get(profile_)->NotifyTaskStateChanged(*this);
 }
 
 void ActorTask::Act(std::vector<std::unique_ptr<ToolRequest>>&& actions,
diff --git a/chrome/browser/actor/aggregated_journal_file_serializer.cc b/chrome/browser/actor/aggregated_journal_file_serializer.cc
index 314f48c..c9665e7 100644
--- a/chrome/browser/actor/aggregated_journal_file_serializer.cc
+++ b/chrome/browser/actor/aggregated_journal_file_serializer.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/actor/aggregated_journal_file_serializer.h"
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
 #include "base/task/task_traits.h"
@@ -37,14 +33,14 @@
     packet.AddSlice(message.data(), message.size());
 
     auto [preamble, preamble_size] = packet.GetProtoPreamble();
-    if (!file_handle_->WriteAtCurrentPosAndCheck(base::span(
-            reinterpret_cast<const uint8_t*>(preamble), preamble_size))) {
+    if (!file_handle_->WriteAtCurrentPosAndCheck(UNSAFE_TODO(base::span(
+            reinterpret_cast<const uint8_t*>(preamble), preamble_size)))) {
       return;
     }
 
     for (const perfetto::Slice& slice : packet.slices()) {
-      if (!file_handle_->WriteAtCurrentPosAndCheck(base::span(
-              static_cast<const uint8_t*>(slice.start), slice.size))) {
+      if (!file_handle_->WriteAtCurrentPosAndCheck(UNSAFE_TODO(base::span(
+              static_cast<const uint8_t*>(slice.start), slice.size)))) {
         return;
       }
     }
diff --git a/chrome/browser/actor/aggregated_journal_in_memory_serializer.cc b/chrome/browser/actor/aggregated_journal_in_memory_serializer.cc
index 445f26c..c1a330c 100644
--- a/chrome/browser/actor/aggregated_journal_in_memory_serializer.cc
+++ b/chrome/browser/actor/aggregated_journal_in_memory_serializer.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/actor/aggregated_journal_in_memory_serializer.h"
 
+#include "base/compiler_specific.h"
 #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
 
 namespace actor {
@@ -58,13 +54,13 @@
     perfetto::TracePacket packet;
     packet.AddSlice(buffer.data(), buffer.size());
     auto [preamble, preamble_size] = packet.GetProtoPreamble();
-    auto preamble_span =
-        base::span(reinterpret_cast<const uint8_t*>(preamble), preamble_size);
+    auto preamble_span = UNSAFE_TODO(
+        base::span(reinterpret_cast<const uint8_t*>(preamble), preamble_size));
     result_buffer.insert(result_buffer.end(), preamble_span.begin(),
                          preamble_span.end());
     for (const perfetto::Slice& slice : packet.slices()) {
-      auto data_span =
-          base::span(static_cast<const uint8_t*>(slice.start), slice.size);
+      auto data_span = UNSAFE_TODO(
+          base::span(static_cast<const uint8_t*>(slice.start), slice.size));
       result_buffer.insert(result_buffer.end(), data_span.begin(),
                            data_span.end());
     }
diff --git a/chrome/browser/actor/ui/BUILD.gn b/chrome/browser/actor/ui/BUILD.gn
index 53ed57f6..93591da 100644
--- a/chrome/browser/actor/ui/BUILD.gn
+++ b/chrome/browser/actor/ui/BUILD.gn
@@ -98,6 +98,8 @@
     "mock_actor_ui_tab_controller.h",
     "mock_event_dispatcher.cc",
     "mock_event_dispatcher.h",
+    "mock_handoff_button_controller.cc",
+    "mock_handoff_button_controller.h",
   ]
   testonly = true
   public_deps = [
diff --git a/chrome/browser/actor/ui/DIR_METADATA b/chrome/browser/actor/ui/DIR_METADATA
new file mode 100644
index 0000000..aff2c86
--- /dev/null
+++ b/chrome/browser/actor/ui/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail: {
+  component: "UI>Browser>Privacy Sandbox"
+}
+team_email: "koilos@google.com"
+buganizer_public: {
+  component_id: 1706459
+}
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller.cc b/chrome/browser/actor/ui/actor_ui_tab_controller.cc
index 1f3aec3a..a57f942 100644
--- a/chrome/browser/actor/ui/actor_ui_tab_controller.cc
+++ b/chrome/browser/actor/ui/actor_ui_tab_controller.cc
@@ -6,6 +6,8 @@
 
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/actor/actor_keyed_service.h"
+#include "chrome/browser/actor/ui/actor_ui_tab_controller_interface.h"
+#include "chrome/browser/actor/ui/handoff_button_controller.h"
 #include "components/tabs/public/tab_interface.h"
 
 namespace actor::ui {
@@ -77,6 +79,13 @@
       FROM_HERE, base::BindOnce(std::move(callback), true));
 
   // TODO(crbug.com/428216197): Only notify relevant UI components on change.
+  if (GetHandoffButtonController()) {
+    // TODO(crbug.com/433568221): Update the visibility logic when ActorOverlay
+    // is integrated into the Tab Controller (For now it's set to true when the
+    // tab is active).
+    GetHandoffButtonController()->UpdateState(
+        current_ui_tab_state_.handoff_button, current_tab_active_status_);
+  }
 }
 
 void ActorUiTabController::SetActiveTaskId(TaskId task_id) {
@@ -107,7 +116,19 @@
 }
 
 void ActorUiTabController::SetHandoffButtonVisibility(bool is_visible) {
-  // TODO(crbug.com/425952887): Implement this function.
+  bool should_be_visible = is_visible && current_tab_active_status_;
+  GetHandoffButtonController()->UpdateState(
+      current_ui_tab_state_.handoff_button, should_be_visible);
+  VLOG(4) << "Handoff button turned " << (should_be_visible ? "ON" : "OFF");
+}
+
+HandoffButtonController* ActorUiTabController::GetHandoffButtonController() {
+  if (!handoff_button_controller_) {
+    handoff_button_controller_ =
+        std::make_unique<HandoffButtonController>(*tab_);
+  }
+
+  return handoff_button_controller_.get();
 }
 
 base::WeakPtr<ActorUiTabControllerInterface>
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller.h b/chrome/browser/actor/ui/actor_ui_tab_controller.h
index a71e3a6..64d8a25 100644
--- a/chrome/browser/actor/ui/actor_ui_tab_controller.h
+++ b/chrome/browser/actor/ui/actor_ui_tab_controller.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/actor/ui/actor_overlay.mojom.h"
 #include "chrome/browser/actor/ui/actor_overlay_view_controller.h"
 #include "chrome/browser/actor/ui/actor_ui_tab_controller_interface.h"
+#include "chrome/browser/actor/ui/handoff_button_controller.h"
 #include "components/tabs/public/tab_interface.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -35,16 +36,22 @@
   base::WeakPtr<ActorUiTabControllerInterface> GetWeakPtr() override;
   void SetActorTaskPaused() override;
   void SetActorTaskResume() override;
+  void SetHandoffButtonVisibility(bool is_visible) override;
 
   void BindActorOverlay(
       mojo::PendingReceiver<mojom::ActorOverlayPageHandler> receiver) override;
-  void SetHandoffButtonVisibility(bool is_visible) override;
+
+ protected:
+  // The Handoff Button controller for this tab.
+  std::unique_ptr<HandoffButtonController> handoff_button_controller_;
 
  private:
   // Called to propagate a UiTabState and tab status change to UI controllers.
   void UpdateState(const UiTabState& ui_tab_state,
                    bool tab_active_status,
                    UiResultCallback callback);
+  // Gets a new or existing handoff button controller for this tab.
+  HandoffButtonController* GetHandoffButtonController();
   // Tab subscriptions:
   // Called when the tab is detached.
   void OnTabWillDetach(tabs::TabInterface* tab,
@@ -70,6 +77,7 @@
 
   raw_ptr<ActorKeyedService> actor_keyed_service_ = nullptr;
   std::unique_ptr<ActorOverlayViewController> actor_overlay_view_controller_;
+
   base::WeakPtrFactory<ActorUiTabController> weak_factory_{this};
 };
 
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller_interface.h b/chrome/browser/actor/ui/actor_ui_tab_controller_interface.h
index 2463a6be..235f5d4c 100644
--- a/chrome/browser/actor/ui/actor_ui_tab_controller_interface.h
+++ b/chrome/browser/actor/ui/actor_ui_tab_controller_interface.h
@@ -7,6 +7,7 @@
 
 #include "chrome/browser/actor/task_id.h"
 #include "chrome/browser/actor/ui/actor_overlay.mojom.h"
+#include "chrome/browser/actor/ui/handoff_button_controller.h"
 #include "chrome/browser/actor/ui/states/actor_overlay_state.h"
 #include "chrome/browser/actor/ui/states/handoff_button_state.h"
 #include "components/tabs/public/tab_interface.h"
@@ -27,6 +28,11 @@
             << "}";
 }
 
+enum class TabScopedUiComponentType {
+  ActorOverlay,
+  HandoffButton,
+};
+
 class ActorUiTabControllerInterface {
  public:
   virtual ~ActorUiTabControllerInterface() = default;
@@ -53,10 +59,12 @@
   // Clears the last active task id actuating on this tab.
   virtual void ClearActiveTaskId() = 0;
 
+  // Sets the visibility of the handoff button.
+  virtual void SetHandoffButtonVisibility(bool is_visible) = 0;
+
   virtual base::WeakPtr<ActorUiTabControllerInterface> GetWeakPtr() = 0;
   virtual void BindActorOverlay(
       mojo::PendingReceiver<mojom::ActorOverlayPageHandler> receiver) = 0;
-  virtual void SetHandoffButtonVisibility(bool is_visible) = 0;
 };
 
 }  // namespace actor::ui
diff --git a/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc b/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc
index 6f923d3..923bdd9 100644
--- a/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc
+++ b/chrome/browser/actor/ui/actor_ui_tab_controller_unittest.cc
@@ -8,7 +8,11 @@
 #include "chrome/browser/actor/actor_keyed_service.h"
 #include "chrome/browser/actor/actor_keyed_service_factory.h"
 #include "chrome/browser/actor/actor_keyed_service_fake.h"
+#include "chrome/browser/actor/ui/actor_ui_tab_controller_interface.h"
 #include "chrome/browser/actor/ui/mock_actor_ui_state_manager.h"
+#include "chrome/browser/actor/ui/mock_handoff_button_controller.h"
+#include "chrome/browser/actor/ui/states/actor_overlay_state.h"
+#include "chrome/browser/actor/ui/states/handoff_button_state.h"
 #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
 #include "chrome/common/actor/action_result.h"
 #include "chrome/test/base/testing_profile.h"
@@ -22,6 +26,26 @@
 using ::testing::_;
 using ::testing::Return;
 
+class ActorUiTabControllerFake : public ActorUiTabController {
+ public:
+  explicit ActorUiTabControllerFake(tabs::TabInterface& tab,
+                                    ActorKeyedService* actor_service)
+      : ActorUiTabController(tab, actor_service) {
+    handoff_button_controller_ =
+        std::make_unique<MockHandoffButtonController>(tab);
+
+    mock_handoff_button_controller_ = static_cast<MockHandoffButtonController*>(
+        handoff_button_controller_.get());
+  }
+
+  MockHandoffButtonController* mock_handoff_button_controller() {
+    return mock_handoff_button_controller_;
+  }
+
+ private:
+  raw_ptr<MockHandoffButtonController> mock_handoff_button_controller_;
+};
+
 class ActorUiTabControllerTest : public testing::Test {
  public:
   ActorUiTabControllerTest() = default;
@@ -38,7 +62,7 @@
                            &ActorUiTabControllerTest::BuildActorKeyedService,
                            base::Unretained(this)))
                    .Build();
-    actor_ui_tab_controller_ = std::make_unique<ActorUiTabController>(
+    actor_ui_tab_controller_ = std::make_unique<ActorUiTabControllerFake>(
         mock_tab_, actor_keyed_service());
     ON_CALL(mock_tab_, GetBrowserWindowInterface())
         .WillByDefault(Return(&mock_browser_window_interface_));
@@ -73,7 +97,7 @@
         ActorKeyedService::Get(profile()));
   }
 
-  ActorUiTabControllerInterface* actor_ui_tab_controller() {
+  ActorUiTabControllerFake* actor_ui_tab_controller() {
     return actor_ui_tab_controller_.get();
   }
 
@@ -81,14 +105,21 @@
     return ActorKeyedService::Get(profile())->GetActorUiStateManager();
   }
 
+  MockHandoffButtonController* mock_handoff_button_controller() {
+    return static_cast<MockHandoffButtonController*>(
+        actor_ui_tab_controller()->mock_handoff_button_controller());
+  }
+
   TaskId task_id() { return task_id_; }
 
   TestingProfile* profile() { return profile_.get(); }
 
+  MockTabInterface& mock_tab() { return mock_tab_; }
+
  private:
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestingProfile> profile_;
-  std::unique_ptr<ActorUiTabControllerInterface> actor_ui_tab_controller_;
+  std::unique_ptr<ActorUiTabControllerFake> actor_ui_tab_controller_;
   MockTabInterface mock_tab_;
   MockBrowserWindowInterface mock_browser_window_interface_;
   TaskId task_id_;
@@ -106,5 +137,86 @@
             ActorTask::State::kReflecting);
 }
 
+TEST_F(ActorUiTabControllerTest, OnTabActiveStatusChanged_ChangesVisibility) {
+  // The tab is inactive, so setting it active should make it visible.
+  EXPECT_CALL(*mock_handoff_button_controller(),
+              UpdateState(HandoffButtonState(), true));
+  actor_ui_tab_controller()->OnTabActiveStatusChanged(true, &mock_tab());
+
+  // Now the tab is active. Setting it to inactive should make it invisible.
+  EXPECT_CALL(*mock_handoff_button_controller(),
+              UpdateState(HandoffButtonState(), false));
+  actor_ui_tab_controller()->OnTabActiveStatusChanged(false, &mock_tab());
+}
+
+TEST_F(ActorUiTabControllerTest,
+       OnUiTabStateChange_CallsHandoffControllerWithCorrectStateAndVisibility) {
+  HandoffButtonState handoff_button_state(
+      true, HandoffButtonState::ControlOwnership::kAgent);
+  UiTabState ui_tab_state = UiTabState(
+      ActorOverlayState(true, false, std::nullopt), handoff_button_state);
+  // First, set the tab's status to inactive.
+  ON_CALL(mock_tab(), IsActivated).WillByDefault(Return(false));
+
+  // The visibility will be false since the tab is inactive.
+  EXPECT_CALL(*mock_handoff_button_controller(),
+              UpdateState(handoff_button_state, false));
+
+  actor_ui_tab_controller()->OnUiTabStateChange(ui_tab_state,
+                                                base::DoNothing());
+}
+
+TEST_F(ActorUiTabControllerTest, OnUiTabStateChange_NoOpIfStateIsUnchanged) {
+  UiTabState ui_tab_state = UiTabState(
+      ActorOverlayState(true, false, std::nullopt),
+      HandoffButtonState(true, HandoffButtonState::ControlOwnership::kAgent));
+
+  EXPECT_CALL(*mock_handoff_button_controller(), UpdateState(_, _)).Times(1);
+
+  actor_ui_tab_controller()->OnUiTabStateChange(ui_tab_state,
+                                                base::DoNothing());
+
+  actor_ui_tab_controller()->OnUiTabStateChange(ui_tab_state,
+                                                base::DoNothing());
+}
+
+TEST_F(ActorUiTabControllerTest,
+       SetHandoffButtonVisibility_TrueWhenTabIsActiveAndInputIsTrue) {
+  // First, ensure the tab is active.
+  actor_ui_tab_controller()->OnTabActiveStatusChanged(true, &mock_tab());
+
+  // Expect UpdateState to be called with is_visible set to true.
+  EXPECT_CALL(*mock_handoff_button_controller(),
+              UpdateState(HandoffButtonState(), true));
+
+  actor_ui_tab_controller()->SetHandoffButtonVisibility(true);
+}
+
+TEST_F(ActorUiTabControllerTest,
+       SetHandoffButtonVisibility_FalseWhenTabIsActiveAndInputIsFalse) {
+  // First, ensure the tab is active.
+  actor_ui_tab_controller()->OnTabActiveStatusChanged(true, &mock_tab());
+
+  // Expect UpdateState to be called with is_visible set to false.
+  EXPECT_CALL(*mock_handoff_button_controller(),
+              UpdateState(HandoffButtonState(), false));
+
+  actor_ui_tab_controller()->SetHandoffButtonVisibility(false);
+}
+
+TEST_F(ActorUiTabControllerTest,
+       SetHandoffButtonVisibility_AlwaysFalseWhenTabIsInactive) {
+  // First, ensure the tab is inactive.
+  actor_ui_tab_controller()->OnTabActiveStatusChanged(false, &mock_tab());
+
+  // Expect UpdateState to be called with is_visible set to false.
+  EXPECT_CALL(*mock_handoff_button_controller(),
+              UpdateState(HandoffButtonState(), false))
+      .Times(2);
+
+  actor_ui_tab_controller()->SetHandoffButtonVisibility(true);
+  actor_ui_tab_controller()->SetHandoffButtonVisibility(false);
+}
+
 }  // namespace
 }  // namespace actor::ui
diff --git a/chrome/browser/actor/ui/handoff_button_controller.h b/chrome/browser/actor/ui/handoff_button_controller.h
index 45cca64..9ab948d2 100644
--- a/chrome/browser/actor/ui/handoff_button_controller.h
+++ b/chrome/browser/actor/ui/handoff_button_controller.h
@@ -35,7 +35,7 @@
   HandoffButtonController(const HandoffButtonController&) = delete;
   HandoffButtonController& operator=(const HandoffButtonController&) = delete;
 
-  void UpdateState(const HandoffButtonState& state, bool is_visible);
+  virtual void UpdateState(const HandoffButtonState& state, bool is_visible);
 
  protected:
   void OnButtonPressed();
diff --git a/chrome/browser/actor/ui/mock_handoff_button_controller.cc b/chrome/browser/actor/ui/mock_handoff_button_controller.cc
new file mode 100644
index 0000000..293a38d
--- /dev/null
+++ b/chrome/browser/actor/ui/mock_handoff_button_controller.cc
@@ -0,0 +1,14 @@
+// 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 "chrome/browser/actor/ui/mock_handoff_button_controller.h"
+
+namespace actor::ui {
+
+MockHandoffButtonController::MockHandoffButtonController(
+    tabs::TabInterface& tab_interface)
+    : HandoffButtonController(tab_interface) {}
+MockHandoffButtonController::~MockHandoffButtonController() = default;
+
+}  // namespace actor::ui
diff --git a/chrome/browser/actor/ui/mock_handoff_button_controller.h b/chrome/browser/actor/ui/mock_handoff_button_controller.h
new file mode 100644
index 0000000..985e5a37
--- /dev/null
+++ b/chrome/browser/actor/ui/mock_handoff_button_controller.h
@@ -0,0 +1,27 @@
+// 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 CHROME_BROWSER_ACTOR_UI_MOCK_HANDOFF_BUTTON_CONTROLLER_H_
+#define CHROME_BROWSER_ACTOR_UI_MOCK_HANDOFF_BUTTON_CONTROLLER_H_
+
+#include "chrome/browser/actor/ui/handoff_button_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace actor::ui {
+
+// A mock class for HandoffButtonController.
+class MockHandoffButtonController : public HandoffButtonController {
+ public:
+  explicit MockHandoffButtonController(tabs::TabInterface& tab_interface);
+  ~MockHandoffButtonController() override;
+
+  MOCK_METHOD(void,
+              UpdateState,
+              (const HandoffButtonState& state, bool is_visible),
+              (override));
+};
+
+}  // namespace actor::ui
+
+#endif  // CHROME_BROWSER_ACTOR_UI_MOCK_HANDOFF_BUTTON_CONTROLLER_H_
diff --git a/chrome/browser/ai/ai_language_model.cc b/chrome/browser/ai/ai_language_model.cc
index ed02034..cd07a72 100644
--- a/chrome/browser/ai/ai_language_model.cc
+++ b/chrome/browser/ai/ai_language_model.cc
@@ -502,15 +502,12 @@
 // static
 base::flat_set<std::string_view>
 AILanguageModel::GetSupportedLanguageBaseCodes() {
-  // Comma-separated list of languages that are enabled for the Prompt API.
-  // Specify "*" to enable all supported languages.
+  // Comma-separated language codes to enable; or "*" enables all supported.
   const base::FeatureParam<std::string> kAIPromptAPILanguagesEnabled{
       &blink::features::kAIPromptAPI, "langs", /*default_value=*/"en"};
+  // TODO(crbug.com/394841624): Get supported languages from the model config.
   auto kSupportedBaseLanguages =
       base::MakeFixedFlatSet<std::string_view>({"en", "ja", "es"});
-
-  // TODO(crbug.com/394841624): Using the model execution config instead
-  // of using the hardcoded list.
   return AIUtils::RestrictSupportedLanguagesForFeature(
       base::MakeFlatSet<std::string_view>(kSupportedBaseLanguages),
       kAIPromptAPILanguagesEnabled);
diff --git a/chrome/browser/ai/ai_language_model.h b/chrome/browser/ai/ai_language_model.h
index ffde09b1..bb173656 100644
--- a/chrome/browser/ai/ai_language_model.h
+++ b/chrome/browser/ai/ai_language_model.h
@@ -117,7 +117,7 @@
   static PromptApiMetadata ParseMetadata(
       const optimization_guide::proto::Any& any);
 
-  // Returns a set of (base) language codes that are supported and enabled.
+  // Returns a set of BCP 47 base language codes that are supported and enabled.
   static base::flat_set<std::string_view> GetSupportedLanguageBaseCodes();
 
   // Format the initial prompts, gets the token count, updates the session,
diff --git a/chrome/browser/ai/ai_manager.cc b/chrome/browser/ai/ai_manager.cc
index 2f1543d..b30cb01 100644
--- a/chrome/browser/ai/ai_manager.cc
+++ b/chrome/browser/ai/ai_manager.cc
@@ -458,12 +458,9 @@
           base::StringPrintf(kEmptyExpectedOutputLanguageWarning,
                              "LanguageModel"));
     }
-    if (!AreExpectedLanguagesSupported(
-            options->expected_inputs,
-            AILanguageModel::GetSupportedLanguageBaseCodes()) ||
-        !AreExpectedLanguagesSupported(
-            options->expected_outputs,
-            AILanguageModel::GetSupportedLanguageBaseCodes())) {
+    const auto languages = AILanguageModel::GetSupportedLanguageBaseCodes();
+    if (!AreExpectedLanguagesSupported(options->expected_inputs, languages) ||
+        !AreExpectedLanguagesSupported(options->expected_outputs, languages)) {
       AddMessageToConsoleForUnexpectedLanguage(
           blink::mojom::ConsoleMessageLevel::kError,
           base::StringPrintf(kUnsupportedLanguageError, "LanguageModel"));
@@ -482,13 +479,9 @@
         client,
     blink::mojom::AILanguageModelCreateOptionsPtr options) {
   CHECK(options);
-
-  if (!AreExpectedLanguagesSupported(
-          options->expected_inputs,
-          AILanguageModel::GetSupportedLanguageBaseCodes()) ||
-      !AreExpectedLanguagesSupported(
-          options->expected_outputs,
-          AILanguageModel::GetSupportedLanguageBaseCodes())) {
+  const auto languages = AILanguageModel::GetSupportedLanguageBaseCodes();
+  if (!AreExpectedLanguagesSupported(options->expected_inputs, languages) ||
+      !AreExpectedLanguagesSupported(options->expected_outputs, languages)) {
     AddMessageToConsoleForUnexpectedLanguage(
         blink::mojom::ConsoleMessageLevel::kError,
         base::StringPrintf(kUnsupportedLanguageError, "LanguageModel"));
@@ -765,11 +758,11 @@
         blink::mojom::ConsoleMessageLevel::kWarning,
         base::StringPrintf(kEmptyExpectedOutputLanguageWarning, "Writer"));
   }
-  if (options && !IsLanguagesSupported(options->expected_input_languages,
-                                       options->expected_context_languages,
-                                       options->output_language,
-                                       base::MakeFlatSet<std::string_view>(
-                                           kDefaultSupportedBaseLanguages))) {
+  if (options &&
+      !IsLanguagesSupported(options->expected_input_languages,
+                            options->expected_context_languages,
+                            options->output_language,
+                            AIWriter::GetSupportedLanguageBaseCodes())) {
     AddMessageToConsoleForUnexpectedLanguage(
         blink::mojom::ConsoleMessageLevel::kError,
         base::StringPrintf(kUnsupportedLanguageError, "Writer"));
@@ -790,11 +783,11 @@
         blink::mojom::ConsoleMessageLevel::kWarning,
         base::StringPrintf(kEmptyExpectedOutputLanguageWarning, "Writer"));
   }
-  if (options && !IsLanguagesSupported(options->expected_input_languages,
-                                       options->expected_context_languages,
-                                       options->output_language,
-                                       base::MakeFlatSet<std::string_view>(
-                                           kDefaultSupportedBaseLanguages))) {
+  if (options &&
+      !IsLanguagesSupported(options->expected_input_languages,
+                            options->expected_context_languages,
+                            options->output_language,
+                            AIWriter::GetSupportedLanguageBaseCodes())) {
     AddMessageToConsoleForUnexpectedLanguage(
         blink::mojom::ConsoleMessageLevel::kError,
         base::StringPrintf(kUnsupportedLanguageError, "Writer"));
@@ -839,11 +832,11 @@
         blink::mojom::ConsoleMessageLevel::kWarning,
         base::StringPrintf(kEmptyExpectedOutputLanguageWarning, "Rewriter"));
   }
-  if (options && !IsLanguagesSupported(options->expected_input_languages,
-                                       options->expected_context_languages,
-                                       options->output_language,
-                                       base::MakeFlatSet<std::string_view>(
-                                           kDefaultSupportedBaseLanguages))) {
+  if (options &&
+      !IsLanguagesSupported(options->expected_input_languages,
+                            options->expected_context_languages,
+                            options->output_language,
+                            AIWriter::GetSupportedLanguageBaseCodes())) {
     AddMessageToConsoleForUnexpectedLanguage(
         blink::mojom::ConsoleMessageLevel::kError,
         base::StringPrintf(kUnsupportedLanguageError, "Rewriter"));
@@ -864,11 +857,11 @@
         blink::mojom::ConsoleMessageLevel::kWarning,
         base::StringPrintf(kEmptyExpectedOutputLanguageWarning, "Rewriter"));
   }
-  if (options && !IsLanguagesSupported(options->expected_input_languages,
-                                       options->expected_context_languages,
-                                       options->output_language,
-                                       base::MakeFlatSet<std::string_view>(
-                                           kDefaultSupportedBaseLanguages))) {
+  if (options &&
+      !IsLanguagesSupported(options->expected_input_languages,
+                            options->expected_context_languages,
+                            options->output_language,
+                            AIWriter::GetSupportedLanguageBaseCodes())) {
     AddMessageToConsoleForUnexpectedLanguage(
         blink::mojom::ConsoleMessageLevel::kError,
         base::StringPrintf(kUnsupportedLanguageError, "Rewriter"));
diff --git a/chrome/browser/ai/ai_rewriter.cc b/chrome/browser/ai/ai_rewriter.cc
index be7401e9..671a9a9 100644
--- a/chrome/browser/ai/ai_rewriter.cc
+++ b/chrome/browser/ai/ai_rewriter.cc
@@ -9,8 +9,10 @@
 #include "base/strings/string_util.h"
 #include "chrome/browser/ai/ai_context_bound_object.h"
 #include "chrome/browser/ai/ai_utils.h"
+#include "components/language/core/common/locale_util.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/proto/common_types.pb.h"
+#include "third_party/blink/public/common/features_generated.h"
 #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h"
 
 namespace {
@@ -97,9 +99,26 @@
   proto_options->set_output_tone(ToProtoTone(options->tone));
   proto_options->set_output_format(ToProtoFormat(options->format));
   proto_options->set_output_length(ToProtoLength(options->length));
+  if (options->output_language && !options->output_language->code.empty()) {
+    proto_options->set_output_language(
+        language::ExtractBaseLanguage(options->output_language->code));
+  }
   return proto_options;
 }
 
+// static
+base::flat_set<std::string_view> AIRewriter::GetSupportedLanguageBaseCodes() {
+  // Comma-separated language codes to enable; or "*" enables all supported.
+  const base::FeatureParam<std::string> kAIRewriterAPILanguagesEnabled{
+      &blink::features::kAIWriterAPI, "langs", /*default_value=*/"en"};
+  // TODO(crbug.com/394841624): Get supported languages from the model config.
+  auto kSupportedBaseLanguages =
+      base::MakeFixedFlatSet<std::string_view>({"en", "ja", "es"});
+  return AIUtils::RestrictSupportedLanguagesForFeature(
+      base::MakeFlatSet<std::string_view>(kSupportedBaseLanguages),
+      kAIRewriterAPILanguagesEnabled);
+}
+
 void AIRewriter::Rewrite(
     const std::string& input,
     const std::optional<std::string>& context,
diff --git a/chrome/browser/ai/ai_rewriter.h b/chrome/browser/ai/ai_rewriter.h
index 07167a0..b5ebd7c 100644
--- a/chrome/browser/ai/ai_rewriter.h
+++ b/chrome/browser/ai/ai_rewriter.h
@@ -39,6 +39,9 @@
   static std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions>
   ToProtoOptions(const blink::mojom::AIRewriterCreateOptionsPtr& options);
 
+  // Returns a set of BCP 47 base language codes that are supported and enabled.
+  static base::flat_set<std::string_view> GetSupportedLanguageBaseCodes();
+
   // `blink::mojom::AIRewriter` implementation.
   void Rewrite(const std::string& input,
                const std::optional<std::string>& context,
diff --git a/chrome/browser/ai/ai_summarizer.cc b/chrome/browser/ai/ai_summarizer.cc
index 1158f22..94bca3b 100644
--- a/chrome/browser/ai/ai_summarizer.cc
+++ b/chrome/browser/ai/ai_summarizer.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "chrome/browser/ai/ai_context_bound_object.h"
 #include "chrome/browser/ai/ai_utils.h"
+#include "components/language/core/common/locale_util.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/proto/features/summarize.pb.h"
 #include "components/optimization_guide/proto/string_value.pb.h"
@@ -89,6 +90,10 @@
   proto_options->set_output_type(ToProtoType(options->type));
   proto_options->set_output_format(ToProtoFormat(options->format));
   proto_options->set_output_length(ToProtoLength(options->length));
+  if (options->output_language && !options->output_language->code.empty()) {
+    proto_options->set_output_language(
+        language::ExtractBaseLanguage(options->output_language->code));
+  }
   return proto_options;
 }
 
@@ -103,14 +108,12 @@
 
 // static
 base::flat_set<std::string_view> AISummarizer::GetSupportedLanguageBaseCodes() {
-  // Comma-separated list of languages that are enabled for the Summarizer API.
+  // Comma-separated language codes to enable; or "*" enables all supported.
   const base::FeatureParam<std::string> kAISummarizationAPILanguagesEnabled{
       &blink::features::kAISummarizationAPI, "langs", /*default_value=*/"en"};
+  // TODO(crbug.com/394841624): Get supported languages from the model config.
   auto kSupportedBaseLanguages =
       base::MakeFixedFlatSet<std::string_view>({"en", "ja", "es"});
-
-  // TODO(crbug.com/394841624): Using the model execution config instead
-  // of using the hardcoded list.
   return AIUtils::RestrictSupportedLanguagesForFeature(
       base::MakeFlatSet<std::string_view>(kSupportedBaseLanguages),
       kAISummarizationAPILanguagesEnabled);
diff --git a/chrome/browser/ai/ai_summarizer.h b/chrome/browser/ai/ai_summarizer.h
index c87bdee..37d18c7 100644
--- a/chrome/browser/ai/ai_summarizer.h
+++ b/chrome/browser/ai/ai_summarizer.h
@@ -49,7 +49,8 @@
   // Joins `shared` and `input` contexts with a space and newline as needed.
   static std::string CombineContexts(std::string_view shared,
                                      std::string_view input);
-  // Returns a set of (base) language codes that are supported and enabled.
+
+  // Returns a set of BCP 47 base language codes that are supported and enabled.
   static base::flat_set<std::string_view> GetSupportedLanguageBaseCodes();
 
  private:
diff --git a/chrome/browser/ai/ai_writer.cc b/chrome/browser/ai/ai_writer.cc
index 9b95ec6..b51b092 100644
--- a/chrome/browser/ai/ai_writer.cc
+++ b/chrome/browser/ai/ai_writer.cc
@@ -8,8 +8,10 @@
 #include "base/strings/strcat.h"
 #include "chrome/browser/ai/ai_context_bound_object.h"
 #include "chrome/browser/ai/ai_utils.h"
+#include "components/language/core/common/locale_util.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/proto/common_types.pb.h"
+#include "third_party/blink/public/common/features_generated.h"
 #include "third_party/blink/public/mojom/ai/model_streaming_responder.mojom.h"
 
 namespace {
@@ -89,9 +91,26 @@
   proto_options->set_output_tone(ToProtoTone(options->tone));
   proto_options->set_output_format(ToProtoFormat(options->format));
   proto_options->set_output_length(ToProtoLength(options->length));
+  if (options->output_language && !options->output_language->code.empty()) {
+    proto_options->set_output_language(
+        language::ExtractBaseLanguage(options->output_language->code));
+  }
   return proto_options;
 }
 
+// static
+base::flat_set<std::string_view> AIWriter::GetSupportedLanguageBaseCodes() {
+  // Comma-separated language codes to enable; or "*" enables all supported.
+  const base::FeatureParam<std::string> kAIWriterAPILanguagesEnabled{
+      &blink::features::kAIWriterAPI, "langs", /*default_value=*/"en"};
+  // TODO(crbug.com/394841624): Get supported languages from the model config.
+  auto kSupportedBaseLanguages =
+      base::MakeFixedFlatSet<std::string_view>({"en", "ja", "es"});
+  return AIUtils::RestrictSupportedLanguagesForFeature(
+      base::MakeFlatSet<std::string_view>(kSupportedBaseLanguages),
+      kAIWriterAPILanguagesEnabled);
+}
+
 void AIWriter::Write(const std::string& input,
                      const std::optional<std::string>& context,
                      mojo::PendingRemote<blink::mojom::ModelStreamingResponder>
diff --git a/chrome/browser/ai/ai_writer.h b/chrome/browser/ai/ai_writer.h
index d35fb3d..4df9f7db 100644
--- a/chrome/browser/ai/ai_writer.h
+++ b/chrome/browser/ai/ai_writer.h
@@ -37,6 +37,9 @@
   static std::unique_ptr<optimization_guide::proto::WritingAssistanceApiOptions>
   ToProtoOptions(const blink::mojom::AIWriterCreateOptionsPtr& options);
 
+  // Returns a set of BCP 47 base language codes that are supported and enabled.
+  static base::flat_set<std::string_view> GetSupportedLanguageBaseCodes();
+
   // `blink::mojom::AIWriter` implementation.
   void Write(const std::string& input,
              const std::optional<std::string>& context,
diff --git a/chrome/browser/android/autocomplete/tab_matcher_android.cc b/chrome/browser/android/autocomplete/tab_matcher_android.cc
index 915ab87c..d8ffca5 100644
--- a/chrome/browser/android/autocomplete/tab_matcher_android.cc
+++ b/chrome/browser/android/autocomplete/tab_matcher_android.cc
@@ -171,8 +171,10 @@
   // at least once start here and span until the end of this method.
   JNIEnv* env = base::android::AttachCurrentThread();
   jclass tab_model_clazz = TabModelJniBridge::GetClazz(env);
-  base::android::ScopedJavaLocalRef<jobjectArray> j_tab_model_array(
-      env, env->NewObjectArray(tab_models.size(), tab_model_clazz, nullptr));
+  auto j_tab_model_array =
+      base::android::ScopedJavaLocalRef<jobjectArray>::Adopt(
+          env,
+          env->NewObjectArray(tab_models.size(), tab_model_clazz, nullptr));
   // Get all the hidden and non CCT tabs. Filter the tabs in CCT tabmodel first.
   for (size_t i = 0; i < tab_models.size(); ++i) {
     env->SetObjectArrayElement(j_tab_model_array.obj(), i,
diff --git a/chrome/browser/android/contextualsearch/native_contextual_search_context.cc b/chrome/browser/android/contextualsearch/native_contextual_search_context.cc
index 787eedf..eb9af4c 100644
--- a/chrome/browser/android/contextualsearch/native_contextual_search_context.cc
+++ b/chrome/browser/android/contextualsearch/native_contextual_search_context.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/android/jni_string.h"
+#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "components/translate/core/common/translate_constants.h"
 #include "components/translate/core/language_detection/language_detection_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -18,6 +19,12 @@
     JNIEnv* env,
     const base::android::JavaRef<jobject>& obj) {
   java_object_.Reset(env, obj);
+
+  bool use_snippet_as_subtitle =
+      base::FeatureList::IsEnabled(chrome::android::kTouchToSearchCallout) &&
+      chrome::android::kTouchToSearchCalloutSnippetAsSubtitle.Get();
+
+  ContextualSearchContext::SetUseSnippetAsSubtitle(use_snippet_as_subtitle);
 }
 
 NativeContextualSearchContext::~NativeContextualSearchContext() = default;
diff --git a/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc b/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
index 1498a0e..d9fd98f 100644
--- a/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
+++ b/chrome/browser/android/customtabs/tab_interaction_recorder_android.cc
@@ -287,7 +287,7 @@
     const JavaParamRef<jobject>& jtab) {
   TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab);
   if (!tab || !tab->web_contents() || tab->web_contents()->IsBeingDestroyed()) {
-    return ScopedJavaLocalRef<jobject>(env, nullptr);
+    return ScopedJavaLocalRef<jobject>::Adopt(env, nullptr);
   }
 
   auto* recorder =
@@ -301,7 +301,7 @@
     const JavaParamRef<jobject>& jtab) {
   TabAndroid* tab = TabAndroid::GetNativeTab(env, jtab);
   if (!tab || !tab->web_contents() || tab->web_contents()->IsBeingDestroyed()) {
-    return ScopedJavaLocalRef<jobject>(env, nullptr);
+    return ScopedJavaLocalRef<jobject>::Adopt(env, nullptr);
   }
 
   TabInteractionRecorderAndroid::CreateForWebContents(tab->web_contents());
diff --git a/chrome/browser/android/feedback/screenshot_task.cc b/chrome/browser/android/feedback/screenshot_task.cc
index db5c798..54781d5 100644
--- a/chrome/browser/android/feedback/screenshot_task.cc
+++ b/chrome/browser/android/feedback/screenshot_task.cc
@@ -31,7 +31,8 @@
     scoped_refptr<base::RefCountedMemory> png_data) {
   if (png_data.get()) {
     size_t size = png_data->size();
-    ScopedJavaLocalRef<jbyteArray> jbytes(env, env->NewByteArray(size));
+    auto jbytes =
+        ScopedJavaLocalRef<jbyteArray>::Adopt(env, env->NewByteArray(size));
     env->SetByteArrayRegion(jbytes.obj(), 0, size, (jbyte*)png_data->front());
     Java_ScreenshotTask_onBytesReceived(env, callback, jbytes);
   } else {
diff --git a/chrome/browser/android/historical_tab_saver.cc b/chrome/browser/android/historical_tab_saver.cc
index cddeed8..b57a924 100644
--- a/chrome/browser/android/historical_tab_saver.cc
+++ b/chrome/browser/android/historical_tab_saver.cc
@@ -51,7 +51,7 @@
 
   for (int i = 0; i < jbyte_buffers_count; ++i) {
     web_contents_states.emplace_back(
-        ScopedJavaLocalRef<jobject>(
+        ScopedJavaLocalRef<jobject>::Adopt(
             env, env->GetObjectArrayElement(jbyte_buffers.obj(), i)),
         saved_state_versions[i]);
   }
@@ -77,7 +77,7 @@
   for (size_t i = 0; i < array_length; ++i) {
     auto jtab_group_id = env->GetObjectArrayElement(jtab_group_ids.obj(), i);
     std::optional<tab_groups::TabGroupId> tab_group_id = JavaTokenToTabGroupId(
-        env, ScopedJavaLocalRef<jobject>(env, jtab_group_id));
+        env, ScopedJavaLocalRef<jobject>::Adopt(env, jtab_group_id));
     tab_group_ids.push_back(std::move(tab_group_id));
   }
   return tab_group_ids;
@@ -324,11 +324,11 @@
   std::vector<WebContentsStateByteBuffer> web_contents_states =
       AllTabsWebContentsStateByteBuffer(env, jbyte_buffers,
                                         std::move(saved_state_versions));
-  CreateHistoricalGroup(TabModelList::FindNativeTabModelForJavaObject(
-                            ScopedJavaLocalRef<jobject>(env, jtab_model.obj())),
-                        tab_group_id, saved_tab_group_id, title, (int)jcolor,
-                        std::move(tabs_android),
-                        std::move(web_contents_states));
+  CreateHistoricalGroup(
+      TabModelList::FindNativeTabModelForJavaObject(
+          ScopedJavaLocalRef<jobject>::Adopt(env, jtab_model.obj())),
+      tab_group_id, saved_tab_group_id, title, (int)jcolor,
+      std::move(tabs_android), std::move(web_contents_states));
 }
 
 static void JNI_HistoricalTabSaverImpl_CreateHistoricalBulkClosure(
@@ -358,7 +358,7 @@
                                         std::move(saved_state_versions));
   CreateHistoricalBulkClosure(
       TabModelList::FindNativeTabModelForJavaObject(
-          ScopedJavaLocalRef<jobject>(env, jtab_model.obj())),
+          ScopedJavaLocalRef<jobject>::Adopt(env, jtab_model.obj())),
       std::move(tab_group_ids), std::move(saved_tab_group_ids),
       std::move(group_titles), std::move(group_colors),
       std::move(per_tab_optional_tab_group_ids),
diff --git a/chrome/browser/android/metrics/android_session_durations_service.cc b/chrome/browser/android/metrics/android_session_durations_service.cc
index c63d50e..6f5995b 100644
--- a/chrome/browser/android/metrics/android_session_durations_service.cc
+++ b/chrome/browser/android/metrics/android_session_durations_service.cc
@@ -102,8 +102,7 @@
           sync_service, identity_manager);
 
   password_session_duration_metrics_recorder_ = std::make_unique<
-      password_manager::PasswordSessionDurationsMetricsRecorder>(pref_service,
-                                                                 sync_service);
+      password_manager::PasswordSessionDurationsMetricsRecorder>(sync_service);
 
   msbb_session_metrics_recorder_ =
       std::make_unique<unified_consent::MsbbSessionDurationsMetricsRecorder>(
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.cc b/chrome/browser/android/recently_closed_tabs_bridge.cc
index 9e09fc3..705bb255 100644
--- a/chrome/browser/android/recently_closed_tabs_bridge.cc
+++ b/chrome/browser/android/recently_closed_tabs_bridge.cc
@@ -305,7 +305,7 @@
   }
 
   auto* model = TabModelList::FindNativeTabModelForJavaObject(
-      ScopedJavaLocalRef<jobject>(env, jtab_model.obj()));
+      ScopedJavaLocalRef<jobject>::Adopt(env, jtab_model.obj()));
   if (model == nullptr) {
     return false;
   }
@@ -329,7 +329,7 @@
   }
 
   auto* model = TabModelList::FindNativeTabModelForJavaObject(
-      ScopedJavaLocalRef<jobject>(env, jtab_model.obj()));
+      ScopedJavaLocalRef<jobject>::Adopt(env, jtab_model.obj()));
   if (model == nullptr) {
     return false;
   }
@@ -352,7 +352,7 @@
   }
 
   auto* model = TabModelList::FindNativeTabModelForJavaObject(
-      ScopedJavaLocalRef<jobject>(env, jtab_model.obj()));
+      ScopedJavaLocalRef<jobject>::Adopt(env, jtab_model.obj()));
   if (model == nullptr) {
     return false;
   }
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 76d87d8..74baab5 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -114,8 +114,6 @@
 
 namespace tabs {
 
-DEFINE_HANDLE_FACTORY(TabInterface);
-
 // static
 TabInterface* TabInterface::GetFromContents(
     content::WebContents* web_contents) {
@@ -408,6 +406,10 @@
       resource_coordinator::ResourceCoordinatorTabHelper::IsLoaded(
           web_contents_.get()));
 
+  const SessionID session_id =
+      sessions::SessionTabHelper::IdForTab(web_contents_.get());
+  CHECK(session_id.is_valid());
+  SetSessionId(session_id.id());
   SetWindowSessionID(session_window_id_);
 
   ContextMenuHelper::FromWebContents(web_contents())
@@ -517,6 +519,7 @@
   // Remove the link from the native WebContents to |this|, since the
   // lifetimes of the two objects are no longer intertwined.
   TabAndroidHelper::SetTabForWebContents(released_contents, nullptr);
+  ClearSessionId();
 
   synced_tab_delegate_->ResetWebContents();
 }
diff --git a/chrome/browser/android/tab_android_unittest.cc b/chrome/browser/android/tab_android_unittest.cc
index 38d62b8..e135e42 100644
--- a/chrome/browser/android/tab_android_unittest.cc
+++ b/chrome/browser/android/tab_android_unittest.cc
@@ -59,7 +59,7 @@
     if (!java_tab_.is_null()) {
       // Call the destroy() method on the Java TabImpl object.
       // This will trigger TabAndroid::Destroy() via JNI.
-      base::android::ScopedJavaLocalRef<jclass> tab_impl_class(
+      auto tab_impl_class = base::android::ScopedJavaLocalRef<jclass>::Adopt(
           env_, env_->GetObjectClass(java_tab_.obj()));
       ASSERT_FALSE(tab_impl_class.is_null());
 
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
index 3e9a8c7..381737bb 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
@@ -169,7 +169,7 @@
     jmethodID getApplication = env->GetMethodID(
         activityThread, "getApplication", "()Landroid/app/Application;");
     jobject context = env->CallObjectMethod(at, getApplication);
-    return base::android::ScopedJavaLocalRef<jobject>(env, context);
+    return base::android::ScopedJavaLocalRef<jobject>::Adopt(env, context);
   }
 
   base::android::ScopedJavaLocalRef<jobject> GetActivityFrom(
diff --git a/chrome/browser/apps/app_service/app_icon/web_app_icon_test_helper.cc b/chrome/browser/apps/app_service/app_icon/web_app_icon_test_helper.cc
index ef26cce..3051c81 100644
--- a/chrome/browser/apps/app_service/app_icon/web_app_icon_test_helper.cc
+++ b/chrome/browser/apps/app_service/app_icon/web_app_icon_test_helper.cc
@@ -52,7 +52,7 @@
   }
 
   base::test::TestFuture<bool> future;
-  icon_manager().WriteData(app_id, std::move(icon_bitmaps), {}, {},
+  icon_manager().WriteData(app_id, std::move(icon_bitmaps), {}, {}, {},
                            future.GetCallback());
   bool success = future.Get();
   EXPECT_TRUE(success);
diff --git a/chrome/browser/apps/icon_standardizer.cc b/chrome/browser/apps/icon_standardizer.cc
index 14f6f03..ec284e9a 100644
--- a/chrome/browser/apps/icon_standardizer.cc
+++ b/chrome/browser/apps/icon_standardizer.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/apps/icon_standardizer.h"
 
+#include "base/compiler_specific.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkMaskFilter.h"
@@ -65,7 +61,8 @@
     bool does_row_have_visible_pixels = false;
 
     for (int x = 0; x < width; x++) {
-      if (SkColorGetA(nativeRow ? nativeRow[x] : pixmap.getColor(x, y)) >
+      if (UNSAFE_TODO(
+              SkColorGetA(nativeRow ? nativeRow[x] : pixmap.getColor(x, y))) >
           kMinimumVisibleAlpha) {
         gfx::PointF current_point(x, y);
         max_distance =
@@ -83,7 +80,8 @@
     }
 
     for (int x = width - 1; x > 0; x--) {
-      if (SkColorGetA(nativeRow ? nativeRow[x] : pixmap.getColor(x, y)) >
+      if (UNSAFE_TODO(
+              SkColorGetA(nativeRow ? nativeRow[x] : pixmap.getColor(x, y))) >
           kMinimumVisibleAlpha) {
         gfx::PointF current_point(x, y);
         max_distance =
@@ -117,13 +115,13 @@
     for (int x = 0; x < width; x++) {
       SkColor target_color;
 
-      if (SkColorGetA(src_color[x]) < 1) {
+      if (UNSAFE_TODO(SkColorGetA(src_color[x])) < 1) {
         target_color = SK_ColorTRANSPARENT;
       } else {
         target_color = SK_ColorRED;
       }
 
-      preview_color[x] = target_color;
+      UNSAFE_TODO(preview_color[x]) = target_color;
     }
   }
 
@@ -176,7 +174,7 @@
   for (int y = 0; y < preview.height(); ++y) {
     SkColor* src_color = reinterpret_cast<SkColor*>(preview.getAddr32(0, y));
     for (int x = 0; x < preview.width(); ++x) {
-      if (SkColorGetA(src_color[x]) >= kMinimumVisibleAlpha) {
+      if (UNSAFE_TODO(SkColorGetA(src_color[x])) >= kMinimumVisibleAlpha) {
         total_pixel_difference++;
       }
     }
diff --git a/chrome/browser/apps/icon_standardizer_unittest.cc b/chrome/browser/apps/icon_standardizer_unittest.cc
index 028aeba..abf30ff 100644
--- a/chrome/browser/apps/icon_standardizer_unittest.cc
+++ b/chrome/browser/apps/icon_standardizer_unittest.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/apps/icon_standardizer.h"
 
+#include "base/compiler_specific.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkImage.h"
@@ -31,7 +27,7 @@
   uint8_t* first_data = reinterpret_cast<uint8_t*>(first_bitmap.getPixels());
   uint8_t* second_data = reinterpret_cast<uint8_t*>(second_bitmap.getPixels());
   for (size_t i = 0; i < size; ++i) {
-    if (first_data[i] != second_data[i]) {
+    if (UNSAFE_TODO(first_data[i]) != UNSAFE_TODO(second_data[i])) {
       bitmaps_equal = false;
       break;
     }
@@ -44,7 +40,7 @@
   const int y = kIconSize / 2;
   SkColor* src_color = reinterpret_cast<SkColor*>(bitmap.getAddr32(0, y));
   for (int x = 0; x < bitmap.width(); ++x) {
-    if (src_color[x] == SK_ColorWHITE) {
+    if (UNSAFE_TODO(src_color[x]) == SK_ColorWHITE) {
       return true;
     }
   }
diff --git a/chrome/browser/apps/platform_apps/app_speech_recognition_browsertest.cc b/chrome/browser/apps/platform_apps/app_speech_recognition_browsertest.cc
index 6b91f96..360568e 100644
--- a/chrome/browser/apps/platform_apps/app_speech_recognition_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_speech_recognition_browsertest.cc
@@ -2,14 +2,10 @@
 // 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 <memory>
 
 #include "base/command_line.h"
+#include "base/compiler_specific.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -29,7 +25,7 @@
         testing::UnitTest::GetInstance()->current_test_info();
     // For SpeechRecognitionTest.SpeechFromBackgroundPage test, we need to
     // fake the speech input to make tests run OK in bots.
-    if (!strcmp(test_info->name(), "SpeechFromBackgroundPage")) {
+    if (!UNSAFE_TODO(strcmp(test_info->name(), "SpeechFromBackgroundPage"))) {
       fake_speech_recognition_manager_ =
           std::make_unique<content::FakeSpeechRecognitionManager>();
       fake_speech_recognition_manager_->set_should_send_fake_response(true);
diff --git a/chrome/browser/ash/app_list/search/local_image_search/image_annotation_worker.cc b/chrome/browser/ash/app_list/search/local_image_search/image_annotation_worker.cc
index 737f4db..65da4bb6 100644
--- a/chrome/browser/ash/app_list/search/local_image_search/image_annotation_worker.cc
+++ b/chrome/browser/ash/app_list/search/local_image_search/image_annotation_worker.cc
@@ -324,7 +324,9 @@
                        weak_ptr_factory_.GetWeakPtr()),
         base::Seconds(std::pow(kRetryDelay, num_retries_passed_)));
     num_retries_passed_ += 1;
-    image_content_annotator_->set_num_retries_passed(num_retries_passed_);
+    if (use_ica_) {
+      image_content_annotator_->set_num_retries_passed(num_retries_passed_);
+    }
     return;
   }
 
diff --git a/chrome/browser/ash/app_mode/web_app/BUILD.gn b/chrome/browser/ash/app_mode/web_app/BUILD.gn
index 1d1afa3..10b297a 100644
--- a/chrome/browser/ash/app_mode/web_app/BUILD.gn
+++ b/chrome/browser/ash/app_mode/web_app/BUILD.gn
@@ -14,8 +14,6 @@
     "kiosk_web_app_manager.h",
     "kiosk_web_app_service_launcher.cc",
     "kiosk_web_app_service_launcher.h",
-    "web_kiosk_browser_controller_ash.cc",
-    "web_kiosk_browser_controller_ash.h",
   ]
   public_deps = [
     "//base",
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.cc b/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.cc
deleted file mode 100644
index 19f36b6..0000000
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.h"
-
-namespace ash {
-
-WebKioskBrowserControllerAsh::WebKioskBrowserControllerAsh(
-    web_app::WebAppProvider& provider,
-    Browser* browser,
-    webapps::AppId app_id)
-    : WebKioskBrowserControllerBase(provider, browser, app_id) {}
-
-WebKioskBrowserControllerAsh::~WebKioskBrowserControllerAsh() = default;
-
-}  // namespace ash
diff --git a/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.h b/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.h
deleted file mode 100644
index ff6e71b..0000000
--- a/chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_APP_MODE_WEB_APP_WEB_KIOSK_BROWSER_CONTROLLER_ASH_H_
-#define CHROME_BROWSER_ASH_APP_MODE_WEB_APP_WEB_KIOSK_BROWSER_CONTROLLER_ASH_H_
-
-#include "chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.h"
-
-#include "components/webapps/common/web_app_id.h"
-
-namespace ash {
-
-// Applies web Kiosk restrictions to the browser in Ash.
-class WebKioskBrowserControllerAsh
-    : public chromeos::WebKioskBrowserControllerBase {
- public:
-  WebKioskBrowserControllerAsh(web_app::WebAppProvider& provider,
-                               Browser* browser,
-                               webapps::AppId app_id);
-
-  WebKioskBrowserControllerAsh(const WebKioskBrowserControllerAsh&) = delete;
-  WebKioskBrowserControllerAsh& operator=(const WebKioskBrowserControllerAsh&) =
-      delete;
-  ~WebKioskBrowserControllerAsh() override;
-
-};
-
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_APP_MODE_WEB_APP_WEB_KIOSK_BROWSER_CONTROLLER_ASH_H_
diff --git a/chrome/browser/ash/boca/DEPS b/chrome/browser/ash/boca/DEPS
index 7bd6c91..55144b7 100644
--- a/chrome/browser/ash/boca/DEPS
+++ b/chrome/browser/ash/boca/DEPS
@@ -52,4 +52,10 @@
   "content_settings_handler_unittest.cc": [
       "+chrome/browser/content_settings/host_content_settings_map_factory.h",
   ],
+  "on_task_locked_session_navigation_throttle_interactive_ui_test.cc": [
+      "+chrome/browser/preloading/scoped_prewarm_feature_list.h",
+  ],
+  "on_task_session_manager_browsertest.cc": [
+      "+chrome/browser/preloading/scoped_prewarm_feature_list.h",
+  ]
 }
diff --git a/chrome/browser/ash/boca/on_task/on_task_locked_session_navigation_throttle_interactive_ui_test.cc b/chrome/browser/ash/boca/on_task/on_task_locked_session_navigation_throttle_interactive_ui_test.cc
index 1307b3c..38012d2 100644
--- a/chrome/browser/ash/boca/on_task/on_task_locked_session_navigation_throttle_interactive_ui_test.cc
+++ b/chrome/browser/ash/boca/on_task/on_task_locked_session_navigation_throttle_interactive_ui_test.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/ash/boca/on_task/on_task_system_web_app_manager_impl.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/platform_util.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -189,6 +190,11 @@
     embedded_test_server()->AddDefaultHandlers(GetChromeTestDataDir());
     ASSERT_TRUE(embedded_test_server()->Start());
   }
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 IN_PROC_BROWSER_TEST_F(OnTaskLockedSessionNavigationThrottleInteractiveUITest,
diff --git a/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc b/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc
index d976f29..da7fdeb 100644
--- a/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc
+++ b/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ash/boca/boca_manager_factory.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/platform_util.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -153,6 +154,10 @@
   net::EmbeddedTestServer* https_server() { return &https_server_; }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   content::ContentMockCertVerifier mock_cert_verifier_;
   net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
   raw_ptr<FakeOnTaskNotificationsManagerDelegate>
diff --git a/chrome/browser/ash/child_accounts/OWNERS b/chrome/browser/ash/child_accounts/OWNERS
index 79195d9..6172fce 100644
--- a/chrome/browser/ash/child_accounts/OWNERS
+++ b/chrome/browser/ash/child_accounts/OWNERS
@@ -1 +1,4 @@
+# TODO(433734945): Remove agawronska after transition completes.
 agawronska@chromium.org
+zhangwenyu@google.com
+longbowei@google.com
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index 5b6fb8e..d74f8d33 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -109,7 +109,6 @@
     "//chrome/browser/chromeos/printing/print_preview",
     "//chrome/browser/chromeos/video_conference",
     "//chrome/browser/extensions",
-    "//chrome/browser/image_decoder:image_decoder",
     "//chrome/browser/media/router/discovery/access_code:access_code_cast_feature",
     "//chrome/browser/media/webrtc",
     "//chrome/browser/profiles:profile",
diff --git a/chrome/browser/ash/dbus/BUILD.gn b/chrome/browser/ash/dbus/BUILD.gn
index 210748e..9efd0d2 100644
--- a/chrome/browser/ash/dbus/BUILD.gn
+++ b/chrome/browser/ash/dbus/BUILD.gn
@@ -76,6 +76,7 @@
     "//chrome/browser/ash/arc/fileapi",
     "//chrome/browser/ash/arc/session",
     "//chrome/browser/ash/arc/tracing",
+    "//chrome/browser/ash/bruschetta",
     "//chrome/browser/ash/crostini",
     "//chrome/browser/ash/login/lock",
     "//chrome/browser/ash/net",
diff --git a/chrome/browser/ash/dbus/DEPS b/chrome/browser/ash/dbus/DEPS
index 43bf8855..094938e 100644
--- a/chrome/browser/ash/dbus/DEPS
+++ b/chrome/browser/ash/dbus/DEPS
@@ -21,6 +21,7 @@
   "+chrome/browser/ash/arc/tracing",
   "+chromeos/ash/experiences/arc/video",
   "+chrome/browser/ash/borealis",
+  "+chrome/browser/ash/bruschetta",
   "+chrome/browser/ash/crostini",
   "+chrome/browser/ash/exo",
   "+chrome/browser/ash/fusebox",
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.cc b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
index 996e8f0..ab1baab 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
@@ -15,6 +15,7 @@
 #include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/metrics/field_trial.h"
+#include "chrome/browser/ash/bruschetta/bruschetta_util.h"
 #include "chrome/browser/ash/crostini/crostini_features.h"
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_features.h"
@@ -105,6 +106,13 @@
                      weak_ptr_factory_.GetWeakPtr()));
   exported_object->ExportMethod(
       chromeos::kChromeFeaturesServiceInterface,
+      chromeos::kChromeFeaturesServiceIsBruschettaEnabledMethod,
+      base::BindRepeating(&ChromeFeaturesServiceProvider::IsBruschettaEnabled,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&ChromeFeaturesServiceProvider::OnExported,
+                     weak_ptr_factory_.GetWeakPtr()));
+  exported_object->ExportMethod(
+      chromeos::kChromeFeaturesServiceInterface,
       chromeos::kChromeFeaturesServiceIsCrostiniEnabledMethod,
       base::BindRepeating(&ChromeFeaturesServiceProvider::IsCrostiniEnabled,
                           weak_ptr_factory_.GetWeakPtr()),
@@ -361,6 +369,18 @@
   std::move(response_sender).Run(std::move(response));
 }
 
+void ChromeFeaturesServiceProvider::IsBruschettaEnabled(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  Profile* profile = GetSenderProfile(method_call, &response_sender);
+  if (!profile) {
+    return;
+  }
+
+  bool answer = !bruschetta::GetInstallableConfigs(profile).empty();
+  SendResponse(method_call, std::move(response_sender), answer);
+}
+
 void ChromeFeaturesServiceProvider::IsCrostiniEnabled(
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.h b/chrome/browser/ash/dbus/chrome_features_service_provider.h
index a8307fb..3ec4395 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.h
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.h
@@ -76,6 +76,9 @@
   // this dbus method.
   void GetFeatureParams(dbus::MethodCall* method_call,
                         dbus::ExportedObject::ResponseSender response_sender);
+  void IsBruschettaEnabled(
+      dbus::MethodCall* method_call,
+      dbus::ExportedObject::ResponseSender response_sender);
   void IsCrostiniEnabled(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);
   void IsCryptohomeDistributedModelEnabled(
diff --git a/chrome/browser/autofill/android/OWNERS b/chrome/browser/autofill/android/OWNERS
index 682b910..731670ee 100644
--- a/chrome/browser/autofill/android/OWNERS
+++ b/chrome/browser/autofill/android/OWNERS
@@ -1,5 +1 @@
-file://components/autofill/android/OWNERS
-
-# Payments-relevant files
-per-file autofill_image_fetcher_impl.*=file://components/autofill/core/browser/payments/ANDROID_OWNERS
-per-file personal_data_manager_android.*=file://components/autofill/core/browser/payments/ANDROID_OWNERS
+ file://components/autofill/android/OWNERS
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/OWNERS b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/OWNERS
deleted file mode 100644
index 1982797..0000000
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Payments-relevant files
-per-file AutofillImageFetcher*.java=file://components/autofill/core/browser/payments/ANDROID_OWNERS
-per-file AutofillUiUtils.java=file://components/autofill/core/browser/payments/ANDROID_OWNERS
-per-file PersonalDataManager*.java=file://components/autofill/core/browser/payments/ANDROID_OWNERS
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
index 76c3638..9052003 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -1065,6 +1065,16 @@
     }
 
     /**
+     * @param guid The GUID of the credit card.
+     * @return Whether the card is eligible for benefits, based on its `guid`.
+     */
+    public boolean isCardEligibleForBenefits(String guid) {
+        ThreadUtils.assertOnUiThread();
+        return PersonalDataManagerJni.get()
+                .isCardEligibleForBenefits(mPersonalDataManagerAndroid, guid);
+    }
+
+    /**
      * Enables or disables the card benefit showing feature.
      *
      * @param enable True to enable showing card benefits, false otherwise.
@@ -1217,5 +1227,8 @@
         BankAccount[] getMaskedBankAccounts(long nativePersonalDataManagerAndroid);
 
         Ewallet[] getEwallets(long nativePersonalDataManagerAndroid);
+
+        boolean isCardEligibleForBenefits(
+                long nativePersonalDataManagerAndroid, @JniType("std::string") String guid);
     }
 }
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 68c7a51..2d2154f9 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -840,4 +840,14 @@
   return reinterpret_cast<intptr_t>(personal_data_manager_android);
 }
 
+jboolean PersonalDataManagerAndroid::IsCardEligibleForBenefits(
+    JNIEnv* env,
+    const std::string& guid) {
+  if (const CreditCard* card =
+          payments_data_manager().GetCreditCardByGUID(guid)) {
+    return payments_data_manager().IsCardEligibleForBenefits(*card);
+  }
+  return false;
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.h b/chrome/browser/autofill/android/personal_data_manager_android.h
index 7daf705..b32c12b 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.h
+++ b/chrome/browser/autofill/android/personal_data_manager_android.h
@@ -252,6 +252,10 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jewallet);
 
+  // Returns whether a card with the specified `guid` is eligible for card
+  // benefits.
+  jboolean IsCardEligibleForBenefits(JNIEnv* env, const std::string& guid);
+
  private:
   ~PersonalDataManagerAndroid() override;
 
diff --git a/chrome/browser/autofill/automated_tests/cache_replayer.cc b/chrome/browser/autofill/automated_tests/cache_replayer.cc
index 60e7550..6145757 100644
--- a/chrome/browser/autofill/automated_tests/cache_replayer.cc
+++ b/chrome/browser/autofill/automated_tests/cache_replayer.cc
@@ -1,10 +1,6 @@
 // Copyright 2019 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
 
 #include "chrome/browser/autofill/automated_tests/cache_replayer.h"
 
diff --git a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/OWNERS b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/OWNERS
deleted file mode 100644
index 7b25154..0000000
--- a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Payments-relevant files
-per-file PersonalDataManagerTest.java=file://components/autofill/core/browser/payments/ANDROID_OWNERS
diff --git a/chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper_desktop_browsertest.cc b/chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper_desktop_browsertest.cc
index 9c7bfc7..66f322d 100644
--- a/chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper_desktop_browsertest.cc
+++ b/chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper_desktop_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/containers/circular_deque.h"
 #include "build/build_config.h"
 #include "chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/cert_verifier_browser_test.h"
 #include "chrome/browser/ui/browser.h"
@@ -36,6 +37,10 @@
   void WaitForDidChangeVisibleSecurityState() { run_loop_.Run(); }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::RunLoop run_loop_;
 };
 
@@ -66,6 +71,10 @@
   }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   breadcrumbs::ScopedEnableBreadcrumbsForTesting enable_breadcrumbs_;
 };
 
diff --git a/chrome/browser/browser_switcher/browser_switcher_sitelist.cc b/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
index f4f9a4a..60c7ed2 100644
--- a/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_sitelist.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 "chrome/browser/browser_switcher/browser_switcher_sitelist.h"
 
 #include <string.h>
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
index 40a606d0..bcf2947a 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -820,7 +820,6 @@
 IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest,
                        ClearingCookiesAlsoClearsPasswordAccountStorageOptIn) {
   const char kTestEmail[] = "foo@gmail.com";
-  PrefService* prefs = GetProfile()->GetPrefs();
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
   signin::IdentityManager* identity_manager =
@@ -831,23 +830,22 @@
   // TODO(crbug.com/375024026): Revisit.
   sync_service->GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, false);
-  ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      prefs, sync_service));
+  ASSERT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   signin::ClearPrimaryAccount(identity_manager);
   RemoveAndWait(chrome_browsing_data_remover::DATA_TYPE_SITE_DATA);
   signin::MakePrimaryAccountAvailable(identity_manager, kTestEmail,
                                       signin::ConsentLevel::kSignin);
 
-  EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      prefs, sync_service));
+  EXPECT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 }
 
 IN_PROC_BROWSER_TEST_F(
     BrowsingDataRemoverBrowserTest,
     ClearingCookiesWithFilterAlsoClearsPasswordAccountStorageSetting) {
   const char kTestEmail[] = "foo@gmail.com";
-  PrefService* prefs = GetProfile()->GetPrefs();
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
   signin::IdentityManager* identity_manager =
@@ -857,8 +855,8 @@
 
   sync_service->GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, false);
-  ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      prefs, sync_service));
+  ASSERT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   // Clearing cookies for some random domain should have no effect on the
   // setting.
@@ -873,8 +871,8 @@
   }
   signin::MakePrimaryAccountAvailable(identity_manager, kTestEmail,
                                       signin::ConsentLevel::kSignin);
-  EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      prefs, sync_service));
+  EXPECT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   // Clearing cookies for google.com should clear the setting.
   signin::ClearPrimaryAccount(identity_manager);
@@ -888,13 +886,12 @@
   }
   signin::MakePrimaryAccountAvailable(identity_manager, kTestEmail,
                                       signin::ConsentLevel::kSignin);
-  EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      prefs, sync_service));
+  EXPECT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 }
 
 IN_PROC_BROWSER_TEST_F(BrowsingDataRemoverBrowserTest, ClearSiteData) {
   const char kTestEmail[] = "foo@gmail.com";
-  PrefService* prefs = GetProfile()->GetPrefs();
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
   signin::IdentityManager* identity_manager =
@@ -959,8 +956,8 @@
 
     sync_service->GetUserSettings()->SetSelectedType(
         syncer::UserSelectableType::kPasswords, false);
-    ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-        prefs, sync_service));
+    ASSERT_FALSE(
+        password_manager::features_util::IsAccountStorageEnabled(sync_service));
     signin::ClearPrimaryAccount(identity_manager);
     ClearSiteDataAndWait(test_case.origin, test_case.cookie_partition_key,
                          test_case.storage_key, {});
@@ -969,10 +966,10 @@
 
     if (test_case.expects_keep_optin_pref) {
       EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-          prefs, sync_service));
+          sync_service));
     } else {
       EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-          prefs, sync_service));
+          sync_service));
     }
   }
 }
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 8f7c958..53c58286 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -1799,8 +1799,8 @@
         CreateTaskCompletionClosure(
             TracingDataType::kDisableAutoSigninForProfilePasswords));
   }
-  if (account_store && password_manager::features_util::IsAccountStorageEnabled(
-                           profile_->GetPrefs(), sync_service)) {
+  if (account_store &&
+      password_manager::features_util::IsAccountStorageEnabled(sync_service)) {
     account_store->DisableAutoSignInForOrigins(
         url_filter,
         CreateTaskCompletionClosure(
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 45414c8..756e1a29 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -4042,7 +4042,7 @@
 #endif
     );
     ASSERT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-        GetProfile()->GetPrefs(), sync_service()));
+        sync_service()));
   }
 };
 
diff --git a/chrome/browser/chrome_browser_interface_binders_webui.cc b/chrome/browser/chrome_browser_interface_binders_webui.cc
index 8ab5d1b4..1b0e320 100644
--- a/chrome/browser/chrome_browser_interface_binders_webui.cc
+++ b/chrome/browser/chrome_browser_interface_binders_webui.cc
@@ -83,6 +83,7 @@
 #include "chrome/browser/new_tab_page/modules/v2/calendar/google_calendar.mojom.h"
 #include "chrome/browser/new_tab_page/modules/v2/calendar/outlook_calendar.mojom.h"
 #include "chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption.mojom.h"
+#include "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom.h"
 #include "chrome/browser/new_tab_page/new_tab_page_util.h"
 #include "chrome/browser/ui/lens/lens_overlay_untrusted_ui.h"
 #include "chrome/browser/ui/lens/lens_side_panel_untrusted_ui.h"
@@ -649,6 +650,9 @@
                                          SuggestInternalsUI>(map);
 
   RegisterWebUIControllerInterfaceBinder<
+      password_manager::mojom::PageHandlerFactory, PasswordManagerUI>(map);
+
+  RegisterWebUIControllerInterfaceBinder<
       customize_color_scheme_mode::mojom::
           CustomizeColorSchemeModeHandlerFactory,
       CustomizeChromeUI, settings::SettingsUI>(map);
@@ -689,6 +693,11 @@
         file_suggestion::mojom::DriveSuggestionHandler, NewTabPageUI>(map);
   }
 
+  if (base::FeatureList::IsEnabled(ntp_features::kNtpTabGroupsModule)) {
+    RegisterWebUIControllerInterfaceBinder<ntp::tab_groups::mojom::PageHandler,
+                                           NewTabPageUI>(map);
+  }
+
   if (base::FeatureList::IsEnabled(
           ntp_features::kNtpMostRelevantTabResumptionModule)) {
     RegisterWebUIControllerInterfaceBinder<
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index c306ca4..38142c0 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/scoped_test_mv2_enabler.h"
 #include "chrome/browser/login_detection/login_detection_util.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
 #include "chrome/browser/tab_contents/navigation_metrics_recorder.h"
 #include "chrome/browser/ui/browser.h"
@@ -333,6 +334,12 @@
     EXPECT_FALSE(contents1->GetSiteInstance()->IsRelatedSiteInstance(
         contents2->GetSiteInstance()));
   }
+
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, NoTarget) {
diff --git a/chrome/browser/chrome_security_exploit_browsertest.cc b/chrome/browser/chrome_security_exploit_browsertest.cc
index 47338e5..c3c6db9 100644
--- a/chrome/browser/chrome_security_exploit_browsertest.cc
+++ b/chrome/browser/chrome_security_exploit_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -182,7 +183,13 @@
 
 class WebstoreSecurityExploitBrowserTest
     : public ChromeSecurityExploitBrowserTest,
-      public testing::WithParamInterface<GURL> {};
+      public testing::WithParamInterface<GURL> {
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
+};
 
 // Tests that a normal web process cannot send a commit for a Chrome
 // Web Store URL. See https://crbug.com/172119.
@@ -380,15 +387,6 @@
       CreateMemoryBackedBlob(payload, payload_type);
   std::string blob_id = blob->GetUUID();
 
-  // Note: a well-behaved renderer would always send the following message here,
-  // but it's actually not necessary for the original attack to succeed, so we
-  // omit it. As a result there are some log warnings from the quota observer.
-  //
-  // IPC::IpcSecurityTestUtil::PwnMessageReceived(
-  //     rfh->GetProcess()->GetChannel(),
-  //     FileSystemHostMsg_OpenFileSystem(22, GURL(target_origin),
-  //                                      storage::kFileSystemTypeTemporary));
-
   GURL target_url =
       GURL("filesystem:" + target_origin + "/temporary/exploit.html");
 
diff --git a/chrome/browser/component_updater/pki_metadata_component_installer.cc b/chrome/browser/component_updater/pki_metadata_component_installer.cc
index 8e2bc26..19526b4 100644
--- a/chrome/browser/component_updater/pki_metadata_component_installer.cc
+++ b/chrome/browser/component_updater/pki_metadata_component_installer.cc
@@ -484,7 +484,6 @@
         SHA256HashValueArrayFromProtoBytes(pinset.static_spki_hashes_sha256());
     pinset_ptr->bad_static_spki_hashes = SHA256HashValueArrayFromProtoBytes(
         pinset.bad_static_spki_hashes_sha256());
-    pinset_ptr->report_uri = pinset.report_uri();
     pinlist_ptr->pinsets.push_back(std::move(pinset_ptr));
   }
 
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_service.cc b/chrome/browser/contextual_cueing/contextual_cueing_service.cc
index db95d51..a1fcd061 100644
--- a/chrome/browser/contextual_cueing/contextual_cueing_service.cc
+++ b/chrome/browser/contextual_cueing/contextual_cueing_service.cc
@@ -423,11 +423,6 @@
   }
 
 #if BUILDFLAG(ENABLE_GLIC)
-  if (!IsGlicTabContextEnabled(pref_service_)) {
-    std::move(callback).Run({});
-    return;
-  }
-
   // Initiate request for suggestions for pinned tabs.
   pinned_tabs_zero_state_suggestions_request_ = MakeZeroStateSuggestionsRequest(
       pinned_web_contents, is_fre, supported_tools, /*is_focused_tab=*/false);
diff --git a/chrome/browser/controlled_frame/controlled_frame_permissions_unittest.cc b/chrome/browser/controlled_frame/controlled_frame_permissions_unittest.cc
index 6d6d16d..691f0f15 100644
--- a/chrome/browser/controlled_frame/controlled_frame_permissions_unittest.cc
+++ b/chrome/browser/controlled_frame/controlled_frame_permissions_unittest.cc
@@ -204,6 +204,7 @@
           ON_DEVICE_SPEECH_RECOGNITION_LANGUAGES_DOWNLOADED:
       case ContentSettingsType::INITIALIZED_TRANSLATIONS:
       case ContentSettingsType::SUSPICIOUS_NOTIFICATION_IDS:
+      case ContentSettingsType::DEVICE_ATTRIBUTES:
         break;
 
       default:
diff --git a/chrome/browser/devtools/device/adb/adb_client_socket.cc b/chrome/browser/devtools/device/adb/adb_client_socket.cc
index f74de49..e04f913b 100644
--- a/chrome/browser/devtools/device/adb/adb_client_socket.cc
+++ b/chrome/browser/devtools/device/adb/adb_client_socket.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/devtools/device/adb/adb_client_socket.h"
 
 #include <stddef.h>
@@ -40,8 +35,8 @@
   CHECK_LE(length, 0xffffu);
   std::string result;
   result.reserve(4);
-  base::AppendHexEncodedByte(reinterpret_cast<const uint8_t*>(&length)[1],
-                             result);
+  base::AppendHexEncodedByte(
+      UNSAFE_TODO(reinterpret_cast<const uint8_t*>(&length)[1]), result);
   base::AppendHexEncodedByte(reinterpret_cast<const uint8_t*>(&length)[0],
                              result);
   return result + message;
diff --git a/chrome/browser/devtools/device/adb/mock_adb_server.cc b/chrome/browser/devtools/device/adb/mock_adb_server.cc
index 92c9661d..c66abee 100644
--- a/chrome/browser/devtools/device/adb/mock_adb_server.cc
+++ b/chrome/browser/devtools/device/adb/mock_adb_server.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/devtools/device/adb/mock_adb_server.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 
 #include <string_view>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
@@ -462,7 +458,8 @@
       EXPECT_TRUE(base::HexStringToUInt(message_header, &message_size));
 
       if (size >= message_size + kAdbMessageHeaderSize) {
-        std::string message_body(data + kAdbMessageHeaderSize, message_size);
+        std::string message_body(UNSAFE_TODO(data + kAdbMessageHeaderSize),
+                                 message_size);
         ProcessCommand(message_body);
         return kAdbMessageHeaderSize + message_size;
       }
diff --git a/chrome/browser/devtools/device/android_device_info_query.cc b/chrome/browser/devtools/device/android_device_info_query.cc
index 8d17f04..4368c334 100644
--- a/chrome/browser/devtools/device/android_device_info_query.cc
+++ b/chrome/browser/devtools/device/android_device_info_query.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 <stddef.h>
 
 #include <array>
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc
index 3df8092..83417c9 100644
--- a/chrome/browser/devtools/device/android_device_manager.cc
+++ b/chrome/browser/devtools/device/android_device_manager.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 "chrome/browser/devtools/device/android_device_manager.h"
 
 #include <stddef.h>
@@ -15,6 +10,7 @@
 #include <string_view>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
@@ -205,7 +201,7 @@
     std::string request = base::StrCat(pieces);
     auto base_buffer =
         base::MakeRefCounted<net::IOBufferWithSize>(request.size());
-    memcpy(base_buffer->data(), request.data(), request.size());
+    UNSAFE_TODO(memcpy(base_buffer->data(), request.data(), request.size()));
     request_ = base::MakeRefCounted<net::DrainableIOBuffer>(
         std::move(base_buffer), request.size());
     timeout_timer_.Start(
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
index c0904f6..e02ff41d 100644
--- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <stddef.h>
 #include <stdint.h>
 
@@ -14,6 +9,7 @@
 #include <unordered_map>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/containers/queue.h"
 #include "base/containers/span.h"
@@ -251,10 +247,11 @@
       // A new message, parse header first.
       DCHECK_GE(buffer.size(), 6u);
       const auto* header = reinterpret_cast<const uint32_t*>(buffer.data());
-      current_message_ = std::make_unique<AdbMessage>(header[0], header[1],
-                                                      header[2], std::string());
-      remaining_body_length_ = header[3];
-      uint32_t magic = header[5];
+      current_message_ =
+          std::make_unique<AdbMessage>(header[0], UNSAFE_TODO(header[1]),
+                                       UNSAFE_TODO(header[2]), std::string());
+      remaining_body_length_ = UNSAFE_TODO(header[3]);
+      uint32_t magic = UNSAFE_TODO(header[5]);
       if ((current_message_->command ^ 0xffffffff) != magic) {
         DCHECK(false) << "Header checksum error";
         base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
@@ -284,7 +281,7 @@
   template <class D>
   void append(D data) {
     std::copy(reinterpret_cast<uint8_t*>(&data),
-              (reinterpret_cast<uint8_t*>(&data)) + sizeof(D),
+              UNSAFE_TODO((reinterpret_cast<uint8_t*>(&data)) + sizeof(D)),
               std::back_inserter(output_buffer_));
   }
 
@@ -294,7 +291,7 @@
     int count = data.length();
     uint32_t sum = 0;
     while (count-- > 0)
-      sum += *x++;
+      sum += *UNSAFE_TODO(x++);
     return sum;
   }
 
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.cc b/chrome/browser/devtools/device/usb/android_usb_socket.cc
index a7b903e93..920d346 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.cc
@@ -2,16 +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/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "chrome/browser/devtools/device/usb/android_usb_socket.h"
 
 #include <stddef.h>
 
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/functional/callback_helpers.h"
 #include "base/notimplemented.h"
 #include "net/base/io_buffer.h"
@@ -130,7 +126,7 @@
 
   size_t bytes_to_copy = static_cast<size_t>(length) > read_buffer_.length() ?
       read_buffer_.length() : static_cast<size_t>(length);
-  memcpy(buffer->data(), read_buffer_.data(), bytes_to_copy);
+  UNSAFE_TODO(memcpy(buffer->data(), read_buffer_.data(), bytes_to_copy));
   if (read_buffer_.length() > bytes_to_copy)
     read_buffer_ = read_buffer_.substr(bytes_to_copy);
   else
@@ -241,7 +237,8 @@
   size_t bytes_to_copy =
       static_cast<size_t>(read_length_) > read_buffer_.length() ?
           read_buffer_.length() : static_cast<size_t>(read_length_);
-  memcpy(read_io_buffer_->data(), read_buffer_.data(), bytes_to_copy);
+  UNSAFE_TODO(
+      memcpy(read_io_buffer_->data(), read_buffer_.data(), bytes_to_copy));
   if (read_buffer_.length() > bytes_to_copy)
     read_buffer_ = read_buffer_.substr(bytes_to_copy);
   else
diff --git a/chrome/browser/devtools/devtools_browsertest.cc b/chrome/browser/devtools/devtools_browsertest.cc
index 42df1a5..7429ded 100644
--- a/chrome/browser/devtools/devtools_browsertest.cc
+++ b/chrome/browser/devtools/devtools_browsertest.cc
@@ -47,6 +47,7 @@
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/developer_tools_policy_handler.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
@@ -389,6 +390,12 @@
   }
 
   raw_ptr<DevToolsWindow> window_;
+
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 class SitePerProcessDevToolsTest : public DevToolsTest {
@@ -3375,6 +3382,11 @@
     policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
   }
   testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 IN_PROC_BROWSER_TEST_F(DevToolsPolicyTest, OpenBlockedDevTools) {
diff --git a/chrome/browser/devtools/devtools_file_system_indexer.cc b/chrome/browser/devtools/devtools_file_system_indexer.cc
index 8e82362..91d850f0 100644
--- a/chrome/browser/devtools/devtools_file_system_indexer.cc
+++ b/chrome/browser/devtools/devtools_file_system_indexer.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/devtools/devtools_file_system_indexer.h"
 
 #include <stddef.h>
@@ -17,6 +12,7 @@
 #include <set>
 
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/containers/heap_array.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
@@ -108,7 +104,7 @@
     trigram_chars = new TrigramChar[256];
     for (size_t i = 0; i < 256; ++i) {
       if (i > 127) {
-        trigram_chars[i] = kUndefinedTrigramChar;
+        UNSAFE_TODO(trigram_chars[i]) = kUndefinedTrigramChar;
         continue;
       }
       char ch = static_cast<char>(i);
@@ -119,12 +115,12 @@
 
       bool is_binary_char = ch < 9 || (ch >= 14 && ch < 32) || ch == 127;
       if (is_binary_char) {
-        trigram_chars[i] = kBinaryTrigramChar;
+        UNSAFE_TODO(trigram_chars[i]) = kBinaryTrigramChar;
         continue;
       }
 
       if (ch < ' ') {
-        trigram_chars[i] = kUndefinedTrigramChar;
+        UNSAFE_TODO(trigram_chars[i]) = kUndefinedTrigramChar;
         continue;
       }
 
@@ -133,11 +129,11 @@
       ch -= ' ';
       char signed_trigram_count = static_cast<char>(kTrigramCharacterCount);
       CHECK(ch >= 0 && ch < signed_trigram_count);
-      trigram_chars[i] = ch;
+      UNSAFE_TODO(trigram_chars[i]) = ch;
     }
   }
   unsigned char uc = static_cast<unsigned char>(c);
-  return trigram_chars[uc];
+  return UNSAFE_TODO(trigram_chars[uc]);
 }
 
 Trigram TrigramAtIndex(const vector<TrigramChar>& trigram_chars, size_t index) {
@@ -204,10 +200,10 @@
   vector<TrigramChar> trigram_chars;
   trigram_chars.reserve(query.size());
   for (size_t i = 0; i < query.size(); ++i) {
-      TrigramChar trigram_char = TrigramCharForChar(data[i]);
-      if (trigram_char == kBinaryTrigramChar)
-        trigram_char = kUndefinedTrigramChar;
-      trigram_chars.push_back(trigram_char);
+    TrigramChar trigram_char = TrigramCharForChar(UNSAFE_TODO(data[i]));
+    if (trigram_char == kBinaryTrigramChar)
+      trigram_char = kUndefinedTrigramChar;
+    trigram_chars.push_back(trigram_char);
   }
   vector<Trigram> trigrams;
   for (size_t i = 0; i + 2 < query.size(); ++i) {
diff --git a/chrome/browser/devtools/protocol/devtools_printtopdf_browsertest.cc b/chrome/browser/devtools/protocol/devtools_printtopdf_browsertest.cc
index 7d640bf..d6317ee 100644
--- a/chrome/browser/devtools/protocol/devtools_printtopdf_browsertest.cc
+++ b/chrome/browser/devtools/protocol/devtools_printtopdf_browsertest.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <optional>
 #include <string>
 #include <vector>
 
 #include "base/base64.h"
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_span.h"
@@ -96,8 +92,8 @@
         break;
     }
 
-    pdf_span_ = base::span<const uint8_t>(
-        reinterpret_cast<const uint8_t*>(pdf_data_.data()), pdf_data_.size());
+    pdf_span_ = UNSAFE_TODO(base::span<const uint8_t>(
+        reinterpret_cast<const uint8_t*>(pdf_data_.data()), pdf_data_.size()));
 
     ASSERT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_span_, &pdf_num_pages_, nullptr));
     ASSERT_GE(pdf_num_pages_, 1);
diff --git a/chrome/browser/download/download_browsertest_utils.cc b/chrome/browser/download/download_browsertest_utils.cc
index 92937e3..58535f5 100644
--- a/chrome/browser/download/download_browsertest_utils.cc
+++ b/chrome/browser/download/download_browsertest_utils.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/download/download_browsertest_utils.h"
 
 #include <optional>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -479,7 +475,8 @@
 
   // Check the contents.
   EXPECT_EQ(value, file_contents);
-  if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0) {
+  if (UNSAFE_TODO(
+          memcmp(file_contents.c_str(), value.c_str(), expected_size)) != 0) {
     return false;
   }
 
diff --git a/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc b/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc
index 65828e64..231d1858 100644
--- a/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc
+++ b/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler.cc
@@ -172,7 +172,7 @@
       type_ == Type::kText ? "Text data" : "Image data",
       /*download_digest_sha256*/ "", type_ == Type::kText ? "text/plain" : "",
       kWebContentUploadDataTransferEventTrigger, content_transfer_method_,
-      content_analysis_info_->GetContentAreaAccountEmail(), content_size_,
+      source_content_area_email_, content_size_,
       content_analysis_info_->referrer_chain(), result, response_,
       CalculateEventResult(content_analysis_info_->settings(),
                            request_handler_result.complies, should_warn));
diff --git a/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler_unittest.cc b/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler_unittest.cc
index c1c223c..b14b8fa 100644
--- a/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler_unittest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/clipboard_request_handler_unittest.cc
@@ -173,6 +173,7 @@
   base::RunLoop run_loop;
   auto validator = helper_->CreateValidator();
   validator.SetDoneClosure(run_loop.QuitClosure());
+  validator.ExpectSourceActiveUser(kSourceEmail);
   validator.ExpectSensitiveDataEvent(
       /*url*/
       kUrl,
@@ -249,6 +250,7 @@
   base::RunLoop run_loop;
   auto validator = helper_->CreateValidator();
   validator.SetDoneClosure(run_loop.QuitClosure());
+  validator.ExpectSourceActiveUser(kSourceEmail);
   validator.ExpectSensitiveDataEvent(
       /*url*/
       kUrl,
diff --git a/chrome/browser/enterprise/connectors/analysis/local_binary_upload_service_unittest.cc b/chrome/browser/enterprise/connectors/analysis/local_binary_upload_service_unittest.cc
index bad1bd1b..55be864 100644
--- a/chrome/browser/enterprise/connectors/analysis/local_binary_upload_service_unittest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/local_binary_upload_service_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/enterprise/connectors/analysis/local_binary_upload_service.h"
 
 #include <array>
diff --git a/chrome/browser/enterprise/connectors/analysis/page_print_analysis_request_unittest.cc b/chrome/browser/enterprise/connectors/analysis/page_print_analysis_request_unittest.cc
index b7448ce..d6d6bce 100644
--- a/chrome/browser/enterprise/connectors/analysis/page_print_analysis_request_unittest.cc
+++ b/chrome/browser/enterprise/connectors/analysis/page_print_analysis_request_unittest.cc
@@ -2,13 +2,9 @@
 // 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 "chrome/browser/enterprise/connectors/analysis/page_print_analysis_request.h"
 
+#include "base/compiler_specific.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/run_loop.h"
@@ -24,7 +20,7 @@
 static base::ReadOnlySharedMemoryRegion CreateFakePage(size_t page_size) {
   base::MappedReadOnlyRegion page =
       base::ReadOnlySharedMemoryRegion::Create(page_size);
-  memset(page.mapping.memory(), 'a', page_size);
+  UNSAFE_TODO(memset(page.mapping.memory(), 'a', page_size));
   return std::move(page.region);
 }
 
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/browser/crypto_utility.cc b/chrome/browser/enterprise/connectors/device_trust/attestation/browser/crypto_utility.cc
index 47a60f9..8ec1c1d 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/browser/crypto_utility.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/browser/crypto_utility.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/enterprise/connectors/device_trust/attestation/browser/crypto_utility.h"
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
@@ -72,7 +68,7 @@
       !CBB_finish(cbb.get(), &der, &der_len)) {
     return false;
   }
-  public_key_info.assign(der, der + der_len);
+  public_key_info.assign(der, UNSAFE_TODO(der + der_len));
   OPENSSL_free(der);
 
   return true;
diff --git a/chrome/browser/enterprise/connectors/device_trust/attestation/browser/google_keys.cc b/chrome/browser/enterprise/connectors/device_trust/attestation/browser/google_keys.cc
index d57da53..7839d29 100644
--- a/chrome/browser/enterprise/connectors/device_trust/attestation/browser/google_keys.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/attestation/browser/google_keys.cc
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/enterprise/connectors/device_trust/attestation/browser/google_keys.h"
 
+#include "base/compiler_specific.h"
+
 namespace enterprise_connectors {
 
 namespace {
@@ -61,7 +58,7 @@
 template <size_t size>
 std::string ZeroTerminatedCharArrayToString(
     const char (&array)[size]) noexcept {
-  return std::string(std::begin(array), std::end(array) - 1);
+  return std::string(std::begin(array), UNSAFE_TODO(std::end(array) - 1));
 }
 
 }  // namespace
diff --git a/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc b/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc
index 5a51e996..9f1b012 100644
--- a/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc
+++ b/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc
@@ -220,8 +220,7 @@
 
 std::string RealtimeReportingClient::GetContentAreaAccountEmail(
     const GURL& url) {
-  return enterprise_connectors::GetActiveContentAreaUser(identity_manager_,
-                                                         url);
+  return GetActiveContentAreaUser(identity_manager_, url);
 }
 
 std::string RealtimeReportingClient::GetBrowserClientId() {
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 7fefd4b..26fed69 100644
--- a/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
+++ b/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
@@ -67,21 +67,18 @@
     client_ = std::make_unique<policy::MockCloudPolicyClient>();
     client_->SetDMToken("fake-token");
 
-    enterprise_connectors::RealtimeReportingClientFactory::GetInstance()
-        ->SetTestingFactory(
-            profile_, base::BindRepeating([](content::BrowserContext* context) {
-              return std::unique_ptr<KeyedService>(
-                  new enterprise_connectors::RealtimeReportingClient(context));
-            }));
-    enterprise_connectors::RealtimeReportingClientFactory::GetForProfile(
-        profile_)
+    RealtimeReportingClientFactory::GetInstance()->SetTestingFactory(
+        profile_, base::BindRepeating([](content::BrowserContext* context) {
+          return std::unique_ptr<KeyedService>(
+              new RealtimeReportingClient(context));
+        }));
+    RealtimeReportingClientFactory::GetForProfile(profile_)
         ->SetBrowserCloudPolicyClientForTesting(client_.get());
 
     reporting_event_router_ = std::make_unique<ReportingEventRouter>(
         RealtimeReportingClientFactory::GetForProfile(profile_));
 
-    enterprise_connectors::RealtimeReportingClientFactory::GetForProfile(
-        profile_)
+    RealtimeReportingClientFactory::GetForProfile(profile_)
         ->SetIdentityManagerForTesting(
             identity_test_environment_.identity_manager());
     identity_test_environment_.MakePrimaryAccountAvailable(
@@ -89,8 +86,7 @@
   }
 
   void TearDown() override {
-    enterprise_connectors::RealtimeReportingClientFactory::GetForProfile(
-        profile_)
+    RealtimeReportingClientFactory::GetForProfile(profile_)
         ->SetBrowserCloudPolicyClientForTesting(nullptr);
   }
 
diff --git a/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.cc b/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.cc
index d2ca1ea..9a74fc3e 100644
--- a/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.cc
+++ b/chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.cc
@@ -89,7 +89,7 @@
     const std::string& expected_profile_username,
     const std::string& expected_profile_identifier,
     const std::optional<std::string>& expected_content_transfer_method) {
-  event_key_ = enterprise_connectors::kKeyUnscannedFileEvent;
+  event_key_ = kKeyUnscannedFileEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -136,7 +136,7 @@
     results_[expected_filenames[i]] = expected_result;
   }
 
-  event_key_ = enterprise_connectors::kKeyUnscannedFileEvent;
+  event_key_ = kKeyUnscannedFileEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -171,7 +171,7 @@
     const std::string& expected_profile_username,
     const std::string& expected_profile_identifier,
     const std::optional<std::string>& expected_scan_id) {
-  event_key_ = enterprise_connectors::kKeyDangerousDownloadEvent;
+  event_key_ = kKeyDangerousDownloadEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -240,7 +240,7 @@
     const std::string& expected_scan_id,
     const std::optional<std::string>& expected_content_transfer_method,
     const std::optional<std::u16string>& expected_user_justification) {
-  event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+  event_key_ = kKeySensitiveDataEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -280,7 +280,7 @@
     const std::string& expected_profile_username,
     const std::string& expected_profile_identifier,
     int64_t expected_content_size) {
-  event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+  event_key_ = kKeySensitiveDataEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -310,7 +310,7 @@
     const std::string& expected_profile_identifier,
     extensions::api::enterprise_reporting_private::DataMaskingEvent
         expected_event) {
-  event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+  event_key_ = kKeySensitiveDataEvent;
   url_ = expected_event.url;
   tab_url_ = expected_event.url;
   username_ = expected_profile_username;
@@ -356,7 +356,7 @@
     scan_ids_[expected_filenames[i]] = expected_scan_ids[i];
   }
 
-  event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+  event_key_ = kKeySensitiveDataEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -406,7 +406,7 @@
     const std::optional<std::string>& expected_content_transfer_method,
     const std::vector<std::optional<std::u16string>>&
         expected_user_justifications) {
-  event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+  event_key_ = kKeySensitiveDataEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -416,26 +416,23 @@
   mimetypes_ = expected_mimetypes;
   trigger_ = expected_trigger;
   content_size_ = expected_content_size;
-  results_[expected_filename] = enterprise_connectors::EventResultToString(
-           enterprise_connectors::EventResult::WARNED);
+  results_[expected_filename] = EventResultToString(EventResult::WARNED);
   username_ = expected_profile_username;
   profile_identifier_ = expected_profile_identifier;
   scan_ids_[expected_filename] = expected_scan_id;
   content_transfer_method_ = expected_content_transfer_method;
   user_justification_ = expected_user_justifications[0];
   EXPECT_CALL(*client_, UploadSecurityEventReport)
-      .WillOnce(
-          [this, expected_filename](bool include_device_info, base::Value::Dict report,
-                 base::OnceCallback<void(policy::CloudPolicyClient::Result)>
-                     callback) {
-            ValidateReport(&report);
-          })
+      .WillOnce([this, expected_filename](
+                    bool include_device_info, base::Value::Dict report,
+                    base::OnceCallback<void(policy::CloudPolicyClient::Result)>
+                        callback) { ValidateReport(&report); })
       .WillOnce([this, expected_filename, expected_user_justifications](
                     bool include_device_info, base::Value::Dict report,
                     base::OnceCallback<void(policy::CloudPolicyClient::Result)>
                         callback) {
-        results_[expected_filename] = enterprise_connectors::EventResultToString(
-            enterprise_connectors::EventResult::BYPASSED);
+        results_[expected_filename] =
+            EventResultToString(EventResult::BYPASSED);
         user_justification_ = expected_user_justifications[1];
         ValidateReport(&report);
         if (!done_closure_.is_null()) {
@@ -462,7 +459,7 @@
         const std::string& expected_profile_identifier,
         const std::string& expected_scan_id,
         const std::optional<std::string>& expected_content_transfer_method) {
-  event_key_ = enterprise_connectors::kKeyDangerousDownloadEvent;
+  event_key_ = kKeyDangerousDownloadEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -486,7 +483,7 @@
                     bool include_device_info, base::Value::Dict report,
                     base::OnceCallback<void(policy::CloudPolicyClient::Result)>
                         callback) {
-        event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+        event_key_ = kKeySensitiveDataEvent;
         threat_type_ = std::nullopt;
         dlp_verdicts_[expected_filename] = expected_dlp_verdict;
         ValidateReport(&report);
@@ -513,7 +510,7 @@
         const std::string& expected_profile_username,
         const std::string& expected_profile_identifier,
         const std::string& expected_scan_id) {
-  event_key_ = enterprise_connectors::kKeySensitiveDataEvent;
+  event_key_ = kKeySensitiveDataEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   source_ = expected_source;
@@ -536,7 +533,7 @@
                     bool include_device_info, base::Value::Dict report,
                     base::OnceCallback<void(policy::CloudPolicyClient::Result)>
                         callback) {
-        event_key_ = enterprise_connectors::kKeyDangerousDownloadEvent;
+        event_key_ = kKeyDangerousDownloadEvent;
         threat_type_ = expected_threat_type;
         dlp_verdicts_.erase(expected_filename);
         ValidateReport(&report);
@@ -558,7 +555,7 @@
     const std::string& expected_result,
     const std::string& expected_profile_username,
     const std::string& expected_profile_identifier) {
-  event_key_ = enterprise_connectors::kKeyDangerousDownloadEvent;
+  event_key_ = kKeyDangerousDownloadEvent;
   url_ = expected_url;
   tab_url_ = expected_tab_url;
   filenames_and_hashes_[expected_filename] = expected_sha256;
@@ -861,7 +858,7 @@
     RealtimeReportingClientFactory::GetInstance()->SetTestingFactory(
         profile, base::BindRepeating([](content::BrowserContext* context) {
           return std::unique_ptr<KeyedService>(
-              new enterprise_connectors::RealtimeReportingClient(context));
+              new RealtimeReportingClient(context));
         }));
   }
 
diff --git a/chrome/browser/enterprise/signals/signals_aggregator_factory.cc b/chrome/browser/enterprise/signals/signals_aggregator_factory.cc
index fc4fa98f..31340c42 100644
--- a/chrome/browser/enterprise/signals/signals_aggregator_factory.cc
+++ b/chrome/browser/enterprise/signals/signals_aggregator_factory.cc
@@ -46,11 +46,15 @@
 #endif  // BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
-#include "components/device_signals/core/browser/agent_signals_collector.h"
-#include "components/device_signals/core/browser/crowdstrike_client.h"
 #include "components/device_signals/core/browser/settings_client.h"
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#include "components/device_signals/core/browser/agent_signals_collector.h"
+#include "components/device_signals/core/browser/crowdstrike_client.h"
+#include "components/device_signals/core/browser/detected_agent_client.h"
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
 namespace enterprise_signals {
 
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
@@ -110,12 +114,16 @@
           service_host));
 #endif  // !BUILDFLAG(IS_ANDROID)
 
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+  collectors.push_back(std::make_unique<device_signals::AgentSignalsCollector>(
+      device_signals::CrowdStrikeClient::Create(),
+      device_signals::DetectedAgentClient::Create()));
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
   collectors.push_back(
       std::make_unique<device_signals::SettingsSignalsCollector>(
           CreateSettingsClient()));
-  collectors.push_back(std::make_unique<device_signals::AgentSignalsCollector>(
-      device_signals::CrowdStrikeClient::Create()));
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 
 #if BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/extensions/activity_log/activity_actions.cc b/chrome/browser/extensions/activity_log/activity_actions.cc
index 6e197ec4..bdb849d 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.cc
+++ b/chrome/browser/extensions/activity_log/activity_actions.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 "chrome/browser/extensions/activity_log/activity_actions.h"
 
 #include <memory>
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc b/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc
index bb74710..e30e52f 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_functions_shared.cc
@@ -840,7 +840,18 @@
 }
 
 void DeveloperPrivateLoadUnpackedFunction::StartFileLoad(
-    const base::FilePath file_path) {
+    base::FilePath file_path) {
+#if BUILDFLAG(IS_ANDROID)
+  // TODO(b/433416481): Make SelectFileDialog return a virtual document path and
+  // remove this code.
+  std::optional<base::FilePath> vp =
+      base::ResolveToVirtualDocumentPath(file_path);
+  if (!vp) {
+    OnLoadComplete(nullptr, file_path, "Failed to resolve (removed?)");
+    return;
+  }
+  file_path = *vp;
+#endif  // BUILDFLAG(IS_ANDROID)
   scoped_refptr<UnpackedInstaller> installer(
       UnpackedInstaller::Create(browser_context()));
   installer->set_be_noisy_on_failure(!fail_quietly_);
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc b/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc
index 8ed09d35..3711c83a 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc
@@ -32,7 +32,7 @@
 #if BUILDFLAG(IS_MAC)
 #include "base/apple/foundation_util.h"
 #include "chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.h"
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 #include "crypto/mac_security_services_lock.h"
 #endif
 
@@ -167,7 +167,7 @@
   password->clear();
 
   OSStatus status;
-  crypto::ScopedKeychainUserInteractionAllowed user_interaction_allowed(
+  crypto::apple::ScopedKeychainUserInteractionAllowed user_interaction_allowed(
       FALSE, &status);
   if (status != noErr)
     return status;
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
index 9365ec4..65217216 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
@@ -840,7 +840,7 @@
 
 bool PasswordsPrivateDelegateImpl::IsAccountStorageEnabled() {
   return password_manager::features_util::IsAccountStorageEnabled(
-      profile_->GetPrefs(), SyncServiceFactory::GetForProfile(profile_));
+      SyncServiceFactory::GetForProfile(profile_));
 }
 
 void PasswordsPrivateDelegateImpl::SetAccountStorageEnabled(
@@ -859,7 +859,7 @@
 
 bool PasswordsPrivateDelegateImpl::ShouldShowAccountStorageSettingToggle() {
   return password_manager::features_util::ShouldShowAccountStorageSettingToggle(
-      profile_->GetPrefs(), SyncServiceFactory::GetForProfile(profile_));
+      SyncServiceFactory::GetForProfile(profile_));
 }
 
 std::vector<api::passwords_private::PasswordUiEntry>
diff --git a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc b/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
index 1d12502..f1ae2e8 100644
--- a/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tcp_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/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "extensions/browser/api/socket/tcp_socket.h"
 
 #include <memory>
diff --git a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
index 4f17717..28d649b 100644
--- a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tls_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/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include <memory>
 #include <utility>
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 3c666c3..dbb0d412 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -27,12 +27,15 @@
 #include "components/tabs/public/tab_interface.h"
 #include "components/translate/core/browser/language_state.h"
 #include "components/translate/core/common/language_detection_details.h"
+#include "components/zoom/zoom_controller.h"
 #include "content/public/browser/navigation_controller.h"
+#include "extensions/browser/extension_zoom_request_client.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/mojom/api_permission_id.mojom-shared.h"
 #include "extensions/common/permissions/permissions_data.h"
+#include "third_party/blink/public/common/page/page_zoom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/base_window.h"
 
@@ -146,6 +149,29 @@
 
 }  // namespace tabs_internal
 
+void ZoomModeToZoomSettings(zoom::ZoomController::ZoomMode zoom_mode,
+                            api::tabs::ZoomSettings* zoom_settings) {
+  DCHECK(zoom_settings);
+  switch (zoom_mode) {
+    case zoom::ZoomController::ZOOM_MODE_DEFAULT:
+      zoom_settings->mode = api::tabs::ZoomSettingsMode::kAutomatic;
+      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerOrigin;
+      break;
+    case zoom::ZoomController::ZOOM_MODE_ISOLATED:
+      zoom_settings->mode = api::tabs::ZoomSettingsMode::kAutomatic;
+      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerTab;
+      break;
+    case zoom::ZoomController::ZOOM_MODE_MANUAL:
+      zoom_settings->mode = api::tabs::ZoomSettingsMode::kManual;
+      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerTab;
+      break;
+    case zoom::ZoomController::ZOOM_MODE_DISABLED:
+      zoom_settings->mode = api::tabs::ZoomSettingsMode::kDisabled;
+      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerTab;
+      break;
+  }
+}
+
 ExtensionFunction::ResponseAction WindowsGetFunction::Run() {
   std::optional<windows::Get::Params> params =
       windows::Get::Params::Create(args());
@@ -957,6 +983,139 @@
   return true;
 }
 
+ExtensionFunction::ResponseAction TabsSetZoomFunction::Run() {
+  std::optional<tabs::SetZoom::Params> params =
+      tabs::SetZoom::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  int tab_id = params->tab_id ? *params->tab_id : -1;
+  std::string error;
+  content::WebContents* web_contents =
+      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
+  if (!web_contents) {
+    return RespondNow(Error(std::move(error)));
+  }
+
+  GURL url(web_contents->GetVisibleURL());
+  if (extension()->permissions_data()->IsRestrictedUrl(url, &error)) {
+    return RespondNow(Error(std::move(error)));
+  }
+
+  zoom::ZoomController* zoom_controller =
+      zoom::ZoomController::FromWebContents(web_contents);
+  double zoom_level = params->zoom_factor > 0
+                          ? blink::ZoomFactorToZoomLevel(params->zoom_factor)
+                          : zoom_controller->GetDefaultZoomLevel();
+
+  auto client = base::MakeRefCounted<ExtensionZoomRequestClient>(extension());
+  if (!zoom_controller->SetZoomLevelByClient(zoom_level, client)) {
+    // Tried to zoom a tab in disabled mode.
+    return RespondNow(Error(tabs_constants::kCannotZoomDisabledTabError));
+  }
+
+  return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
+  std::optional<tabs::GetZoom::Params> params =
+      tabs::GetZoom::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  int tab_id = params->tab_id ? *params->tab_id : -1;
+  std::string error;
+  content::WebContents* web_contents =
+      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
+  if (!web_contents) {
+    return RespondNow(Error(std::move(error)));
+  }
+
+  double zoom_level =
+      zoom::ZoomController::FromWebContents(web_contents)->GetZoomLevel();
+  double zoom_factor = blink::ZoomLevelToZoomFactor(zoom_level);
+
+  return RespondNow(ArgumentList(tabs::GetZoom::Results::Create(zoom_factor)));
+}
+
+ExtensionFunction::ResponseAction TabsSetZoomSettingsFunction::Run() {
+  using api::tabs::ZoomSettings;
+
+  std::optional<tabs::SetZoomSettings::Params> params =
+      tabs::SetZoomSettings::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  int tab_id = params->tab_id ? *params->tab_id : -1;
+  std::string error;
+  content::WebContents* web_contents =
+      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
+  if (!web_contents) {
+    return RespondNow(Error(std::move(error)));
+  }
+
+  GURL url(web_contents->GetVisibleURL());
+  if (extension()->permissions_data()->IsRestrictedUrl(url, &error)) {
+    return RespondNow(Error(std::move(error)));
+  }
+
+  // "per-origin" scope is only available in "automatic" mode.
+  if (params->zoom_settings.scope == tabs::ZoomSettingsScope::kPerOrigin &&
+      params->zoom_settings.mode != tabs::ZoomSettingsMode::kAutomatic &&
+      params->zoom_settings.mode != tabs::ZoomSettingsMode::kNone) {
+    return RespondNow(Error(tabs_constants::kPerOriginOnlyInAutomaticError));
+  }
+
+  // Determine the correct internal zoom mode to set |web_contents| to from the
+  // user-specified |zoom_settings|.
+  zoom::ZoomController::ZoomMode zoom_mode =
+      zoom::ZoomController::ZOOM_MODE_DEFAULT;
+  switch (params->zoom_settings.mode) {
+    case tabs::ZoomSettingsMode::kNone:
+    case tabs::ZoomSettingsMode::kAutomatic:
+      switch (params->zoom_settings.scope) {
+        case tabs::ZoomSettingsScope::kNone:
+        case tabs::ZoomSettingsScope::kPerOrigin:
+          zoom_mode = zoom::ZoomController::ZOOM_MODE_DEFAULT;
+          break;
+        case tabs::ZoomSettingsScope::kPerTab:
+          zoom_mode = zoom::ZoomController::ZOOM_MODE_ISOLATED;
+      }
+      break;
+    case tabs::ZoomSettingsMode::kManual:
+      zoom_mode = zoom::ZoomController::ZOOM_MODE_MANUAL;
+      break;
+    case tabs::ZoomSettingsMode::kDisabled:
+      zoom_mode = zoom::ZoomController::ZOOM_MODE_DISABLED;
+  }
+
+  zoom::ZoomController::FromWebContents(web_contents)->SetZoomMode(zoom_mode);
+
+  return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
+  std::optional<tabs::GetZoomSettings::Params> params =
+      tabs::GetZoomSettings::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  int tab_id = params->tab_id ? *params->tab_id : -1;
+  std::string error;
+  content::WebContents* web_contents =
+      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
+  if (!web_contents) {
+    return RespondNow(Error(std::move(error)));
+  }
+  zoom::ZoomController* zoom_controller =
+      zoom::ZoomController::FromWebContents(web_contents);
+
+  zoom::ZoomController::ZoomMode zoom_mode = zoom_controller->zoom_mode();
+  api::tabs::ZoomSettings zoom_settings;
+  ZoomModeToZoomSettings(zoom_mode, &zoom_settings);
+  zoom_settings.default_zoom_factor =
+      blink::ZoomLevelToZoomFactor(zoom_controller->GetDefaultZoomLevel());
+
+  return RespondNow(
+      ArgumentList(api::tabs::GetZoomSettings::Results::Create(zoom_settings)));
+}
+
 ExtensionFunction::ResponseAction TabsGoForwardFunction::Run() {
   std::optional<tabs::GoForward::Params> params =
       tabs::GoForward::Params::Create(args());
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_android.cc b/chrome/browser/extensions/api/tabs/tabs_api_android.cc
index 67b547a..dfbb599 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_android.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_android.cc
@@ -235,34 +235,6 @@
   return RespondNow(Error(kTabsNotImplemented));
 }
 
-ExtensionFunction::ResponseAction TabsSetZoomFunction::Run() {
-  std::optional<tabs::SetZoom::Params> params =
-      tabs::SetZoom::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-  return RespondNow(Error(kTabsNotImplemented));
-}
-
-ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
-  std::optional<tabs::GetZoom::Params> params =
-      tabs::GetZoom::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-  return RespondNow(Error(kTabsNotImplemented));
-}
-
-ExtensionFunction::ResponseAction TabsSetZoomSettingsFunction::Run() {
-  std::optional<tabs::SetZoomSettings::Params> params =
-      tabs::SetZoomSettings::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-  return RespondNow(Error(kTabsNotImplemented));
-}
-
-ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
-  std::optional<tabs::GetZoomSettings::Params> params =
-      tabs::GetZoomSettings::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-  return RespondNow(Error(kTabsNotImplemented));
-}
-
 TabsDiscardFunction::TabsDiscardFunction() = default;
 TabsDiscardFunction::~TabsDiscardFunction() = default;
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc b/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc
index 290452f..162ebfc5 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc
@@ -95,7 +95,6 @@
 #include "components/tabs/public/tab_group.h"
 #include "components/tabs/public/tab_interface.h"
 #include "components/webapps/common/web_app_id.h"
-#include "components/zoom/zoom_controller.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_frame_host.h"
@@ -106,7 +105,6 @@
 #include "extensions/browser/extension_api_frame_id_map.h"
 #include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/extension_host.h"
-#include "extensions/browser/extension_zoom_request_client.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/file_reader.h"
 #include "extensions/browser/script_executor.h"
@@ -123,7 +121,6 @@
 #include "extensions/common/user_script.h"
 #include "skia/ext/image_operations.h"
 #include "skia/ext/platform_canvas.h"
-#include "third_party/blink/public/common/page/page_zoom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/base/mojom/window_show_state.mojom.h"
@@ -144,7 +141,6 @@
 using content::Referrer;
 using content::WebContents;
 using tabs::TabModel;
-using zoom::ZoomController;
 
 namespace extensions {
 
@@ -391,29 +387,6 @@
 
 }  // namespace
 
-void ZoomModeToZoomSettings(ZoomController::ZoomMode zoom_mode,
-                            api::tabs::ZoomSettings* zoom_settings) {
-  DCHECK(zoom_settings);
-  switch (zoom_mode) {
-    case ZoomController::ZOOM_MODE_DEFAULT:
-      zoom_settings->mode = api::tabs::ZoomSettingsMode::kAutomatic;
-      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerOrigin;
-      break;
-    case ZoomController::ZOOM_MODE_ISOLATED:
-      zoom_settings->mode = api::tabs::ZoomSettingsMode::kAutomatic;
-      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerTab;
-      break;
-    case ZoomController::ZOOM_MODE_MANUAL:
-      zoom_settings->mode = api::tabs::ZoomSettingsMode::kManual;
-      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerTab;
-      break;
-    case ZoomController::ZOOM_MODE_DISABLED:
-      zoom_settings->mode = api::tabs::ZoomSettingsMode::kDisabled;
-      zoom_settings->scope = api::tabs::ZoomSettingsScope::kPerTab;
-      break;
-  }
-}
-
 // Windows ---------------------------------------------------------------------
 
 ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
@@ -1972,138 +1945,6 @@
   return true;
 }
 
-ExtensionFunction::ResponseAction TabsSetZoomFunction::Run() {
-  std::optional<tabs::SetZoom::Params> params =
-      tabs::SetZoom::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-
-  int tab_id = params->tab_id ? *params->tab_id : -1;
-  std::string error;
-  WebContents* web_contents =
-      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
-  if (!web_contents) {
-    return RespondNow(Error(std::move(error)));
-  }
-
-  GURL url(web_contents->GetVisibleURL());
-  if (extension()->permissions_data()->IsRestrictedUrl(url, &error)) {
-    return RespondNow(Error(std::move(error)));
-  }
-
-  ZoomController* zoom_controller =
-      ZoomController::FromWebContents(web_contents);
-  double zoom_level = params->zoom_factor > 0
-                          ? blink::ZoomFactorToZoomLevel(params->zoom_factor)
-                          : zoom_controller->GetDefaultZoomLevel();
-
-  auto client = base::MakeRefCounted<ExtensionZoomRequestClient>(extension());
-  if (!zoom_controller->SetZoomLevelByClient(zoom_level, client)) {
-    // Tried to zoom a tab in disabled mode.
-    return RespondNow(Error(tabs_constants::kCannotZoomDisabledTabError));
-  }
-
-  return RespondNow(NoArguments());
-}
-
-ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
-  std::optional<tabs::GetZoom::Params> params =
-      tabs::GetZoom::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-
-  int tab_id = params->tab_id ? *params->tab_id : -1;
-  std::string error;
-  WebContents* web_contents =
-      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
-  if (!web_contents) {
-    return RespondNow(Error(std::move(error)));
-  }
-
-  double zoom_level =
-      ZoomController::FromWebContents(web_contents)->GetZoomLevel();
-  double zoom_factor = blink::ZoomLevelToZoomFactor(zoom_level);
-
-  return RespondNow(ArgumentList(tabs::GetZoom::Results::Create(zoom_factor)));
-}
-
-ExtensionFunction::ResponseAction TabsSetZoomSettingsFunction::Run() {
-  using api::tabs::ZoomSettings;
-
-  std::optional<tabs::SetZoomSettings::Params> params =
-      tabs::SetZoomSettings::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-
-  int tab_id = params->tab_id ? *params->tab_id : -1;
-  std::string error;
-  WebContents* web_contents =
-      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
-  if (!web_contents) {
-    return RespondNow(Error(std::move(error)));
-  }
-
-  GURL url(web_contents->GetVisibleURL());
-  if (extension()->permissions_data()->IsRestrictedUrl(url, &error)) {
-    return RespondNow(Error(std::move(error)));
-  }
-
-  // "per-origin" scope is only available in "automatic" mode.
-  if (params->zoom_settings.scope == tabs::ZoomSettingsScope::kPerOrigin &&
-      params->zoom_settings.mode != tabs::ZoomSettingsMode::kAutomatic &&
-      params->zoom_settings.mode != tabs::ZoomSettingsMode::kNone) {
-    return RespondNow(Error(tabs_constants::kPerOriginOnlyInAutomaticError));
-  }
-
-  // Determine the correct internal zoom mode to set |web_contents| to from the
-  // user-specified |zoom_settings|.
-  ZoomController::ZoomMode zoom_mode = ZoomController::ZOOM_MODE_DEFAULT;
-  switch (params->zoom_settings.mode) {
-    case tabs::ZoomSettingsMode::kNone:
-    case tabs::ZoomSettingsMode::kAutomatic:
-      switch (params->zoom_settings.scope) {
-        case tabs::ZoomSettingsScope::kNone:
-        case tabs::ZoomSettingsScope::kPerOrigin:
-          zoom_mode = ZoomController::ZOOM_MODE_DEFAULT;
-          break;
-        case tabs::ZoomSettingsScope::kPerTab:
-          zoom_mode = ZoomController::ZOOM_MODE_ISOLATED;
-      }
-      break;
-    case tabs::ZoomSettingsMode::kManual:
-      zoom_mode = ZoomController::ZOOM_MODE_MANUAL;
-      break;
-    case tabs::ZoomSettingsMode::kDisabled:
-      zoom_mode = ZoomController::ZOOM_MODE_DISABLED;
-  }
-
-  ZoomController::FromWebContents(web_contents)->SetZoomMode(zoom_mode);
-
-  return RespondNow(NoArguments());
-}
-
-ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
-  std::optional<tabs::GetZoomSettings::Params> params =
-      tabs::GetZoomSettings::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-
-  int tab_id = params->tab_id ? *params->tab_id : -1;
-  std::string error;
-  WebContents* web_contents =
-      tabs_internal::GetTabsAPIDefaultWebContents(this, tab_id, &error);
-  if (!web_contents) {
-    return RespondNow(Error(std::move(error)));
-  }
-  ZoomController* zoom_controller =
-      ZoomController::FromWebContents(web_contents);
-
-  ZoomController::ZoomMode zoom_mode = zoom_controller->zoom_mode();
-  api::tabs::ZoomSettings zoom_settings;
-  ZoomModeToZoomSettings(zoom_mode, &zoom_settings);
-  zoom_settings.default_zoom_factor =
-      blink::ZoomLevelToZoomFactor(zoom_controller->GetDefaultZoomLevel());
-
-  return RespondNow(
-      ArgumentList(api::tabs::GetZoomSettings::Results::Create(zoom_settings)));
-}
-
 ExtensionFunction::ResponseAction TabsDiscardFunction::Run() {
   std::optional<tabs::Discard::Params> params =
       tabs::Discard::Params::Create(args());
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 46d527d..81425dc6 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -927,7 +927,6 @@
     DetachProtocolClient();
     ExtensionWebRequestApiTest::TearDownOnMainThread();
   }
-
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1375,7 +1374,7 @@
   void RegisterServiceWorker() {
     GURL url =
         embedded_test_server()->GetURL("/workers/service_worker_setup.html");
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+    EXPECT_TRUE(NavigateToURL(url));
     EXPECT_EQ("ok", EvalJs(GetActiveWebContents(), "setup();"));
   }
 
@@ -1393,8 +1392,8 @@
     }
 
     // Navigate to the test page.
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(
-        browser(), embedded_test_server()->GetURL("/workers/simple.html")));
+    EXPECT_TRUE(
+        NavigateToURL(embedded_test_server()->GetURL("/workers/simple.html")));
   }
 
   // Ensures auth required event is received for subresource fetch.
@@ -1634,12 +1633,12 @@
 
   ResultCatcher catcher;
 
-  ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile());
+  ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
   const Extension* extension =
       registry->enabled_extensions().GetByID(last_loaded_extension_id());
   GURL url = extension->GetResourceURL("newTab/a.html");
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  ASSERT_TRUE(NavigateToURL(url));
 
   // There's a link on a.html with target=_blank. Click on it to open it in a
   // new tab.
@@ -1699,10 +1698,10 @@
     const char* exptected_content_incognito_window,
     ContextType context_type) {
   ResultCatcher catcher;
-  catcher.RestrictToBrowserContext(browser()->profile());
+  catcher.RestrictToBrowserContext(profile());
   ResultCatcher catcher_incognito;
   catcher_incognito.RestrictToBrowserContext(
-      browser()->profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true));
+      profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true));
 
   ExtensionTestMessageListener listener("done");
   ExtensionTestMessageListener listener_incognito("done_incognito");
@@ -1717,16 +1716,15 @@
   EXPECT_TRUE(listener.WaitUntilSatisfied());
 
   // This navigation should be redirected.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL("/extensions/test_file.html")));
+  ASSERT_TRUE(NavigateToURL(
+      embedded_test_server()->GetURL("/extensions/test_file.html")));
 
   WebContents* tab = GetActiveWebContents();
   EXPECT_EQ(expected_content_regular_window,
             content::EvalJs(tab, "document.body.textContent"));
 
   // Test that navigation in OTR window is properly redirected.
-  Browser* otr_browser =
-      OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
+  Browser* otr_browser = OpenURLOffTheRecord(profile(), GURL("about:blank"));
 
   if (wait_for_extension_loaded_in_incognito) {
     EXPECT_TRUE(listener_incognito.WaitUntilSatisfied());
@@ -1819,7 +1817,7 @@
       LoadExtension(test_data_dir_.AppendASCII("webrequest_reload"),
                     {.allow_in_incognito = true});
   ASSERT_TRUE(extension);
-  OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
+  OpenURLOffTheRecord(profile(), GURL("about:blank"));
 
   EXPECT_TRUE(listener.WaitUntilSatisfied());
   EXPECT_TRUE(listener_incognito.WaitUntilSatisfied());
@@ -1867,9 +1865,8 @@
   // ping us when it is ready.
   ExtensionTestMessageListener listener_pageready("contentscript_ready",
                                                   ReplyBehavior::kWillReply);
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(
-                     "/extensions/test_file.html?match_webrequest_test")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL(
+      "/extensions/test_file.html?match_webrequest_test")));
   EXPECT_TRUE(listener_pageready.WaitUntilSatisfied());
 
   // The extension and app-generated requests should not have triggered any
@@ -2077,9 +2074,8 @@
       .SetWithholdHostPermissions(true);
   EXPECT_TRUE(listener.WaitUntilSatisfied());
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(
-                     "a.com", "/extensions/cross_site_script.html")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL(
+      "a.com", "/extensions/cross_site_script.html")));
 
   const std::string kCrossSiteHost("b.com");
   EXPECT_FALSE(HasSeenWebRequestInBackgroundScript(extension, profile(),
@@ -2148,9 +2144,8 @@
   EXPECT_TRUE(listener.WaitUntilSatisfied());
 
   // Navigate to example.com, which has a cross-site script to b.com.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(
-                     "example.com", "/extensions/cross_site_script.html")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL(
+      "example.com", "/extensions/cross_site_script.html")));
 
   content::WebContents* web_contents = GetActiveWebContents();
 
@@ -2166,9 +2161,8 @@
 
   // Navigating to b.com (so that the script is hosted on the same origin as
   // the WebContents) should show the extension wants to run.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL(
-                     "b.com", "/extensions/cross_site_script.html")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL(
+      "b.com", "/extensions/cross_site_script.html")));
   EXPECT_EQ(BLOCKED_ACTION_WEB_REQUEST,
             runner->GetBlockedActions(extension->id()));
 }
@@ -3088,16 +3082,15 @@
   // Navigate to the NTP. The request for "fake_ntp_script.js" should not have
   // reached the extension, since it was made by the instant NTP renderer, which
   // is semi-privileged.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
-                                           GURL(chrome::kChromeUINewTabURL)));
+  ASSERT_TRUE(NavigateToURL(GURL(chrome::kChromeUINewTabURL)));
   EXPECT_TRUE(was_ntp_script_loaded(web_contents));
   ASSERT_TRUE(search::IsInstantNTP(web_contents));
   EXPECT_FALSE(was_script_request_intercepted(extension->id()));
 
   // However, when a normal webpage requests the same script, the request should
   // be seen by the extension.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), https_test_server()->GetURL("/page_with_ntp_script.html")));
+  ASSERT_TRUE(
+      NavigateToURL(https_test_server()->GetURL("/page_with_ntp_script.html")));
   EXPECT_TRUE(was_ntp_script_loaded(web_contents));
   ASSERT_FALSE(search::IsInstantNTP(web_contents));
   EXPECT_TRUE(was_script_request_intercepted(extension->id()));
@@ -3225,9 +3218,8 @@
       };
 
   ASSERT_FALSE(GetAndResetOneGoogleBarRequestSeen());
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
-                                           GURL(chrome::kChromeUINewTabURL)));
-  ASSERT_EQ(ntp_test_utils::GetFinalNtpUrl(browser()->profile()),
+  ASSERT_TRUE(NavigateToURL(GURL(chrome::kChromeUINewTabURL)));
+  ASSERT_EQ(ntp_test_utils::GetFinalNtpUrl(profile()),
             GetActiveWebContents()->GetLastCommittedURL());
   WaitForOneGoogleBarDataUpdate();
   ASSERT_TRUE(GetAndResetOneGoogleBarRequestSeen());
@@ -3237,7 +3229,7 @@
 
   // A normal request to |one_google_bar_url()| (i.e. not made by
   // OneGoogleBarFetcher) should be intercepted by extensions.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), one_google_bar_url()));
+  ASSERT_TRUE(NavigateToURL(one_google_bar_url()));
   EXPECT_TRUE(was_script_request_intercepted(extension->id()));
   ASSERT_TRUE(GetAndResetOneGoogleBarRequestSeen());
 }
@@ -3556,7 +3548,7 @@
   const GURL expected_redirect_url_2 =
       embedded_test_server()->GetURL("foo.com", "/simple.html");
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  ASSERT_TRUE(NavigateToURL(url));
 
   content::WebContents* web_contents = GetActiveWebContents();
   ASSERT_TRUE(web_contents);
@@ -3582,7 +3574,7 @@
 
   redirect_ignored_listener.Reset();
   redirect_successful_listener.Reset();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  ASSERT_TRUE(NavigateToURL(url));
 
   // The first extension is the latest installed, hence it's redirect url
   // should take precedence.
@@ -4334,7 +4326,7 @@
     self.initiators = [];
   )";
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  ASSERT_TRUE(NavigateToURL(url));
   std::optional<std::string> result =
       ExecuteScriptAndReturnString(extension_id, profile(), kScript);
   ASSERT_TRUE(result);
@@ -4402,7 +4394,7 @@
     self.initiators = [];
   )";
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_normal));
+  ASSERT_TRUE(NavigateToURL(url_normal));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url_incognito));
   std::optional<std::string> result =
       ExecuteScriptAndReturnString(extension->id(), profile(), kScript);
@@ -4539,7 +4531,7 @@
   GURL redirect_url = embedded_test_server()->GetURL(
       "test.com", "/server-redirect?" + http_url.spec());
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), redirect_url));
+  ASSERT_FALSE(NavigateToURL(redirect_url));
   EXPECT_EQ(final_url, GetActiveWebContents()->GetLastCommittedURL());
 }
 
@@ -4610,7 +4602,7 @@
   GURL redirect_url = embedded_test_server()->GetURL(
       "test.com", "/server-redirect-with-csp?" + http_url.spec());
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), redirect_url));
+  ASSERT_TRUE(NavigateToURL(redirect_url));
   EXPECT_EQ(final_url, GetActiveWebContents()->GetLastCommittedURL());
 }
 
@@ -4870,7 +4862,7 @@
   content::WebContents* web_contents = GetActiveWebContents();
   std::u16string expected_title = u"ScriptDone:UUIDInPackageScriptDone";
   content::TitleWatcher title_watcher(web_contents, expected_title);
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+  ASSERT_TRUE(NavigateToURL(page_url));
   EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
   // Check that the scripts in the web bundle are correctly loaded even when the
   // extension intercepted the request.
@@ -4998,7 +4990,7 @@
 
   GURL page_url = embedded_test_server()->GetURL("/test.html");
   content::WebContents* web_contents = GetActiveWebContents();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+  ASSERT_TRUE(NavigateToURL(page_url));
   EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
 
   std::u16string expected_title1 = u"script loaded";
@@ -5116,7 +5108,7 @@
   std::u16string expected_title = u"200:bar-changed, inserted";
   content::TitleWatcher title_watcher(GetActiveWebContents(), expected_title);
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+  ASSERT_TRUE(NavigateToURL(page_url));
 
   EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
@@ -5219,7 +5211,7 @@
   std::u16string expected_title = u"failed to load";
   content::TitleWatcher title_watcher(GetActiveWebContents(), expected_title);
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+  ASSERT_TRUE(NavigateToURL(page_url));
 
   EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
@@ -5342,7 +5334,7 @@
 
   GURL page_url = embedded_test_server()->GetURL("/test.html");
   content::WebContents* web_contents = GetActiveWebContents();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+  ASSERT_TRUE(NavigateToURL(page_url));
   EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
   {
     std::u16string expected_title = u"redirected";
@@ -5417,8 +5409,7 @@
   std::vector<uint8_t> bundle = builder.CreateBundle();
   web_bundle = std::string(bundle.begin(), bundle.end());
 
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL("/empty.html")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL("/empty.html")));
 
   // In the current implementation, extensions can't redirect requests to
   // Subresource WebBundles.
@@ -5513,7 +5504,7 @@
 
   GURL page_url = embedded_test_server()->GetURL("/test.html");
   content::WebContents* web_contents = GetActiveWebContents();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+  ASSERT_TRUE(NavigateToURL(page_url));
   EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
 
   std::u16string expected_title1 = u"web_bundle.wbn loading canceled";
@@ -5656,7 +5647,7 @@
   // Navigate to the URL that should be redirected, and check that the extension
   // redirects it.
   GURL url = embedded_test_server()->GetURL("original.test", "/hello.html");
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  EXPECT_TRUE(NavigateToURL(url));
   content::WebContents* web_contents = GetActiveWebContents();
   ASSERT_TRUE(web_contents);
   GURL redirected_url =
@@ -5696,7 +5687,7 @@
           "/page_with_iframe.html",
           base::StringPairs{
               {"title1.html", original_iframed_url.spec().c_str()}}));
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), page_with_iframe_url));
+  EXPECT_TRUE(NavigateToURL(page_with_iframe_url));
   content::WebContents* web_contents = GetActiveWebContents();
   ASSERT_TRUE(web_contents);
   EXPECT_EQ(page_with_iframe_url, web_contents->GetLastCommittedURL());
@@ -5766,7 +5757,7 @@
   // navigation happens successfully.
   content::TestNavigationObserver navigation_observer(GetActiveWebContents());
   GURL url = embedded_test_server()->GetURL("redirect.test", "/hello.html");
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+  EXPECT_TRUE(NavigateToURL(url));
   EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
 
   error_observer.WaitForErrors();
@@ -5801,14 +5792,14 @@
         base::Unretained(this)));
     ASSERT_TRUE(proxy_cors_server_.Start());
 
-    PrefService* pref_service = browser()->profile()->GetPrefs();
+    PrefService* pref_service = profile()->GetPrefs();
     pref_service->SetDict(proxy_config::prefs::kProxy,
                           ProxyConfigDictionary::CreateFixedServers(
                               proxy_cors_server_.host_port_pair().ToString(),
                               "accounts.google.com"));
 
     // Flush the proxy configuration change to avoid any races.
-    ProfileNetworkContextServiceFactory::GetForContext(browser()->profile())
+    ProfileNetworkContextServiceFactory::GetForContext(profile())
         ->FlushProxyConfigMonitorForTesting();
     profile()->GetDefaultStoragePartition()->FlushNetworkInterfaceForTesting();
   }
@@ -5960,8 +5951,7 @@
       LoadExtension(test_data_dir_.AppendASCII("webrequest_cors_preflight"));
   ASSERT_TRUE(extension) << message_;
   ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL("/empty.html")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL("/empty.html")));
 
   ExtensionTestMessageListener preflight_listener("cors-preflight-succeeded");
 
@@ -6033,8 +6023,7 @@
   ASSERT_TRUE(extension);
 
   preflight_waiter_ = std::make_unique<base::RunLoop>();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(), embedded_test_server()->GetURL("/empty.html")));
+  ASSERT_TRUE(NavigateToURL(embedded_test_server()->GetURL("/empty.html")));
   ExecuteCorsPreflightedRequest();
 
   ASSERT_TRUE(base::test::RunUntil(
@@ -6173,8 +6162,7 @@
   ASSERT_TRUE(extension);
 
   // Navigate to example.com (a site the extension has access to).
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(),
+  ASSERT_TRUE(NavigateToURL(
       embedded_test_server()->GetURL("example.com", "/simple.html")));
 
   // Validate that we have a single request seen by the extension.
@@ -6201,8 +6189,7 @@
   WaitForReadyMessage();
 
   // Navigate once more to example.com.
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(),
+  ASSERT_TRUE(NavigateToURL(
       embedded_test_server()->GetURL("example.com", "/simple.html")));
 
   // We should now have two records seen by the extension.
@@ -6332,8 +6319,7 @@
   // Navigate to allow.example. This should succeed.
   {
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(
-        browser(),
+    EXPECT_TRUE(NavigateToURL(
         embedded_test_server()->GetURL("allow.example", "/simple.html")));
     EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
   }
@@ -6341,8 +6327,7 @@
   // Now, navigate to block.example. This navigation should be blocked.
   {
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(
-        browser(),
+    EXPECT_FALSE(NavigateToURL(
         embedded_test_server()->GetURL("block.example", "/simple.html")));
     EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, nav_observer.last_net_error_code());
   }
@@ -6392,8 +6377,7 @@
   // Navigate to allow.example. This should succeed.
   {
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(
-        browser(),
+    EXPECT_TRUE(NavigateToURL(
         embedded_test_server()->GetURL("allow.example", "/simple.html")));
     EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
   }
@@ -6401,8 +6385,7 @@
   // Now, navigate to block.example. This navigation should be blocked.
   {
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(
-        browser(),
+    EXPECT_FALSE(NavigateToURL(
         embedded_test_server()->GetURL("block.example", "/simple.html")));
     EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, nav_observer.last_net_error_code());
   }
@@ -6454,8 +6437,7 @@
   // - An error being logged in the extension context, and
   // - The request proceeding.
   content::TestNavigationObserver nav_observer(web_contents);
-  EXPECT_TRUE(ui_test_utils::NavigateToURL(
-      browser(),
+  EXPECT_TRUE(NavigateToURL(
       embedded_test_server()->GetURL("test.example", "/simple.html")));
   EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
 
@@ -6696,8 +6678,7 @@
   {
     content::WebContents* web_contents = GetActiveWebContents();
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(
-        browser(),
+    EXPECT_FALSE(NavigateToURL(
         embedded_test_server()->GetURL("block.example", "/simple.html")));
     EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, nav_observer.last_net_error_code());
   }
@@ -7205,10 +7186,9 @@
 
   ResultCatcher result_catcher;
   content::TestNavigationObserver navigation_observer(GetActiveWebContents());
-  content::RenderFrameHost* frame_host =
-      ui_test_utils::NavigateToURL(browser(), auth_url);
+  ASSERT_TRUE(NavigateToURL(auth_url));
   ASSERT_TRUE(result_catcher.GetNextResult());
-  EXPECT_EQ(auth_url, frame_host->GetLastCommittedURL());
+  EXPECT_EQ(auth_url, GetActiveWebContents()->GetLastCommittedURL());
   EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
 }
 
@@ -7392,7 +7372,7 @@
   // Navigate to the test page.
   GURL requestor_url = embedded_test_server()->GetURL(
       kTestDomain, "/ssl/service_worker_fetch/page.html");
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), requestor_url));
+  ASSERT_TRUE(NavigateToURL(requestor_url));
 
   // Perform a fetch from a worker and validate that it succeeds.
   content::WebContents* web_contents = GetActiveWebContents();
@@ -7472,7 +7452,7 @@
   {
     content::WebContents* web_contents = GetActiveWebContents();
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+    EXPECT_FALSE(NavigateToURL(url));
     EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, nav_observer.last_net_error_code());
   }
 
@@ -7500,7 +7480,7 @@
   {
     content::WebContents* web_contents = GetActiveWebContents();
     content::TestNavigationObserver nav_observer(web_contents);
-    EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+    EXPECT_TRUE(NavigateToURL(url));
     EXPECT_TRUE(nav_observer.last_navigation_succeeded());
     EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
   }
@@ -7768,11 +7748,11 @@
       }));
 
   const GURL kUrlA = embedded_test_server()->GetURL("a.com", "/simple.html");
-  EXPECT_TRUE(NavigateToURLInNewTab(kUrlA));
+  EXPECT_TRUE(NavigateToURL(kUrlA));
 
   const GURL kUrlB = embedded_test_server()->GetURL("b.com", "/simple.html");
 #if !BUILDFLAG(IS_ANDROID)
-  EXPECT_TRUE(NavigateToURLInNewTab(kUrlB));
+  EXPECT_TRUE(NavigateToURL(kUrlB));
 #endif
 
   // Waits until UKM data is recorded.
diff --git a/chrome/browser/extensions/extension_security_exploit_browsertest.cc b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
index 18babd9..fc4e842a 100644
--- a/chrome/browser/extensions/extension_security_exploit_browsertest.cc
+++ b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
@@ -45,7 +45,6 @@
 #include "extensions/common/mojom/service_worker_host.mojom-test-utils.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/test_extension_dir.h"
-#include "ipc/ipc_security_test_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index c9b1a7a..0300e927 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -492,11 +492,9 @@
   int hosted_app_count = 0;
   int legacy_packaged_app_count = 0;
   int platform_app_count = 0;
-  int user_script_count = 0;
   int extension_user_count = 0;
   int extension_external_count = 0;
   int theme_count = 0;
-  int page_action_count = 0;
   int browser_action_count = 0;
   int no_action_count = 0;
   int disabled_for_permissions_count = 0;
@@ -771,7 +769,7 @@
         ++theme_count;
         break;
       case Manifest::TYPE_USER_SCRIPT:
-        ++user_script_count;
+        // No histogram.
         break;
       case Manifest::TYPE_HOSTED_APP:
         ++hosted_app_count;
@@ -811,8 +809,10 @@
     // we want to know how many extensions have a given type of action as part
     // of their code, rather than as part of the extension action redesign
     // (which gives each extension an action).
+    // TODO(devlin): This is wrong -- it's not counting manifest_keys::kAction,
+    // which is the most popular (and only allowed option in MV3+).
     if (extension->manifest()->FindKey(manifest_keys::kPageAction)) {
-      ++page_action_count;
+      // No histogram.
     } else if (extension->manifest()->FindKey(manifest_keys::kBrowserAction)) {
       ++browser_action_count;
     } else {
@@ -1041,9 +1041,6 @@
   base::UmaHistogramCounts100("Extensions.LoadExtensionExternal",
                               extension_external_count);
   base::UmaHistogramCounts100("Extensions.LoadTheme", theme_count);
-  // Histogram name different for legacy reasons.
-  base::UmaHistogramCounts100("PageActionController.ExtensionsWithPageActions",
-                              page_action_count);
   base::UmaHistogramCounts100("Extensions.LoadBrowserAction",
                               browser_action_count);
   base::UmaHistogramCounts100("Extensions.LoadNoExtensionAction",
@@ -1078,11 +1075,7 @@
                                 extension_user_count);
     base::UmaHistogramCounts100("Extensions.LoadExtensionExternal2",
                                 extension_external_count);
-    base::UmaHistogramCounts100("Extensions.LoadUserScript2",
-                                user_script_count);
     base::UmaHistogramCounts100("Extensions.LoadTheme2", theme_count);
-    base::UmaHistogramCounts100("Extensions.ExtensionsWithPageActions",
-                                page_action_count);
     base::UmaHistogramCounts100("Extensions.LoadBrowserAction2",
                                 browser_action_count);
     base::UmaHistogramCounts100("Extensions.LoadNoExtensionAction2",
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d8dc136ed..b325a8f4 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -385,7 +385,7 @@
   },
   {
     "name": "animated-default-browser-promo-in-fre",
-    "owners": [ "bmcclure@google.com", "bling-get-set-up@google.com"],
+    "owners": [ "bmcclure@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 137
   },
   {
@@ -1073,6 +1073,11 @@
     "expiry_milestone": 145
   },
   {
+    "name": "begin-cursor-at-point-tentative-fix",
+    "owners": [ "stkhapugin@chromium.org", "chrome-mobile-search@google.com" ],
+    "expiry_milestone": 145
+  },
+  {
     "name": "best-of-app-fre",
     "owners": [ "thegreenfrog@google.com", "bling-gsu-pod@google.com"],
     "expiry_milestone": 146
@@ -1818,6 +1823,11 @@
     "expiry_milestone": 135
   },
   {
+    "name": "cpe-signal-api",
+    "owners": ["rgod@google.com", "sugoi@chromium.org", "bling-transactions-eng@google.com"],
+    "expiry_milestone": 145
+  },
+  {
     "name": "cras-output-plugin-processor",
     "owners": ["hunghsienchen@google.com", "chromeos-audio@google.com" ],
     "expiry_milestone": 151
@@ -3167,7 +3177,7 @@
     "owners": [
       "tinazwang@chromium.org",
       "sczs@chromium.org",
-      "bling-get-set-up@google.com"
+      "bling-pandamonium@google.com"
     ],
     "expiry_milestone": 140
   },
@@ -3404,7 +3414,7 @@
   },
   {
     "name": "enable-feed-ablation",
-    "owners": [ "adamta@chromium.org", "bling-get-set-up@google.com" ],
+    "owners": [ "adamta@chromium.org", "ginnyhuang@chromium.org", "bling-pandamonium@google.com" ],
     // Long expiry to allow us to disable Discover remotely.
     "expiry_milestone": 150
   },
@@ -3581,7 +3591,7 @@
   },
   {
     "name": "enable-ipad-feed-ghost-cards",
-    "owners": [ "adamta@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "adamta@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 140
   },
   {
@@ -3846,6 +3856,11 @@
     "expiry_milestone": 160
   },
   {
+    "name": "enable-media-link-helpers",
+    "owners": [ "liberato@chromium.org", "media-dev@chromium.org" ],
+    "expiry_milestone": 145
+  },
+  {
     "name": "enable-missive-storage-config",
     "owners" : [ "chrome-reporting-team@google.com", "lbaraz@chromium.org" ],
     "expiry_milestone": 130
@@ -3868,11 +3883,6 @@
     "expiry_milestone": 140
   },
   {
-    "name": "enable-nav-bar-matches-tab-android",
-    "owners": [ "clhager@google.com", "wenyufu@chromium.org", "twellington@chromium.org"],
-    "expiry_milestone": 140
-  },
-  {
     "name": "enable-navigation-capture-refactor-android",
     "owners": [ "muratori@google.org", "lt-web-apps-team@google.com" ],
     "expiry_milestone": 150
@@ -4939,7 +4949,7 @@
   },
   {
     "name": "feed-background-refresh-ios",
-    "owners": [ "adamta@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "adamta@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 140
   },
   {
@@ -4984,7 +4994,7 @@
   },
   {
     "name": "feed-swipe-iph",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 139
   },
   {
@@ -5347,6 +5357,11 @@
     "expiry_milestone": 150
   },
   {
+    "name": "glic-fre-pre-warming",
+    "owners": [ "carlosk@chromium.org", "vollick@chromium.org", "//chrome/browser/glic/OWNERS" ],
+    "expiry_milestone": 146
+  },
+  {
     "name":"glic-panel-reset-on-session-timeout" ,
     "owners": [
       "perrier@chromium.org",
@@ -5379,6 +5394,11 @@
     "expiry_milestone": 144
   },
   {
+    "name": "glic-pre-warming",
+    "owners": [ "carlosk@chromium.org", "vollick@chromium.org", "//chrome/browser/glic/OWNERS" ],
+    "expiry_milestone": 146
+  },
+  {
     "name": "glic-z-order-changes",
     "owners": [
       "andreaxg@google.com",
@@ -5764,7 +5784,7 @@
   },
   {
     "name": "ios-best-features-screen",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 138
   },
   {
@@ -5796,17 +5816,17 @@
   },
   {
     "name": "ios-default-browser-promo-propensity-model",
-    "owners": [ "thegreenfrog@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "thegreenfrog@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 145
   },
   {
     "name": "ios-deprecate-feed-header",
-    "owners": [ "ginnyhuang@chromium.org", "bling-get-set-up@google.com" ],
+    "owners": [ "ginnyhuang@chromium.org", "bling-pandamonium@google.com" ],
     "expiry_milestone": 139
   },
   {
     "name": "ios-docking-promo",
-    "owners": ["bwwilliams@google.com", "bling-get-set-up@google.com"],
+    "owners": ["bwwilliams@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 135
   },
   {
@@ -5816,7 +5836,7 @@
   },
   {
     "name": "ios-expanded-tips",
-    "owners": ["scottyoder@google.com", "bwwilliams@google.com", "bling-get-set-up@google.com"],
+    "owners": ["scottyoder@google.com", "bwwilliams@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 142
   },
   {
@@ -5918,7 +5938,7 @@
   },
   {
     "name": "ios-provides-app-notification-settings",
-    "owners": ["scottyoder@google.com", "bling-get-set-up@google.com"],
+    "owners": ["scottyoder@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 141
   },
   {
@@ -5939,12 +5959,12 @@
   },
   {
     "name": "ios-reactivation-notifications",
-    "owners": ["scottyoder@google.com", "bling-get-set-up@google.com"],
+    "owners": ["scottyoder@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 139
   },
   {
     "name": "ios-segmentation-ephemeral-card-ranker",
-    "owners": [ "thegreenfrog@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "thegreenfrog@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 136
   },
   {
@@ -5978,12 +5998,12 @@
   },
   {
     "name": "ios-start-time-browser-background-remediations",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@chromium.org"],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 136
   },
   {
     "name": "ios-start-time-startup-remediations",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@chromium.org"],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 136
   },
   {
@@ -5993,7 +6013,7 @@
   },
   {
     "name": "ios-welcome-back-screen",
-    "owners": ["bmcclure@google.com", "hiramahmood@google.com", "bling-get-set-up@google.com"],
+    "owners": ["bmcclure@google.com", "hiramahmood@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 141
   },
   {
@@ -6482,7 +6502,7 @@
   },
   {
     "name": "manual-log-uploads-in-the-fre",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 137
   },
   {
@@ -8762,17 +8782,17 @@
   },
   {
     "name": "segmentation-platform-tips-ephemeral-card",
-    "owners": [ "bmcclure@google.com", "bwwilliams@google.com", "bling-flags@google.com", "bling-get-set-up@google.com"],
+    "owners": [ "bmcclure@google.com", "bwwilliams@google.com", "bling-flags@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 134
   },
   {
     "name": "segmented-default-browser-promo",
-    "owners": ["hiramahmood@google.com", "bling-get-set-up@google.com"],
+    "owners": ["hiramahmood@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 135
   },
   {
     "name": "send-tab-ios-push-notifications",
-    "owners": ["hiramahmood@google.com", "bling-get-set-up@google.com"],
+    "owners": ["hiramahmood@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 137
   },
   {
@@ -8822,17 +8842,17 @@
   },
   {
     "name": "set-up-list-in-first-run",
-    "owners": ["hiramahmood@google.com", "bling-get-set-up@google.com"],
+    "owners": ["hiramahmood@google.com", "bling-pandamonium@google.com"],
     "expiry_milestone": 135
   },
   {
     "name": "set-up-list-shortened-duration",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 135
   },
   {
     "name": "set-up-list-without-sign-in-item",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 135
   },
   {
@@ -9739,7 +9759,7 @@
   },
   {
     "name": "updated-fre-screens-sequence",
-    "owners": [ "hiramahmood@google.com", "bling-get-set-up@google.com" ],
+    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 136
   },
   {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f89200ba..4a9808d 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1302,6 +1302,12 @@
     "Glic Panel Reset On Session Timeout";
 const char kGlicPanelResetOnSessionTimeoutDescription[] =
     "Enables resetting the panel position after a session timeout.";
+const char kGlicWarmingName[] = "Glic Pre-Warming";
+const char kGlicWarmingDescription[] =
+    "Enables the pre-warming of the Glic panel's web client.";
+const char kGlicFreWarmingName[] = "Glic FRE Pre-Warming";
+const char kGlicFreWarmingDescription[] =
+    "Enables the pre-warming of Glic's FRE web page.";
 #endif  // #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 
 #if BUILDFLAG(IS_ANDROID)
@@ -5055,12 +5061,6 @@
 const char kNavBarColorAnimationDescription[] =
     "Enables animations for color changes to the OS navigation bar.";
 
-const char kNavBarColorMatchesTabBackgroundName[] =
-    "Nav bar color matches tab background";
-const char kNavBarColorMatchesTabBackgroundDescription[] =
-    "Matches the OS navigation bar color to the background color of the "
-    "active tab.";
-
 const char kNavigationCaptureRefactorAndroidName[] =
     "Navigation Capture refactoring for Chrome on Android";
 const char kNavigationCaptureRefactorAndroidDescription[] =
@@ -5479,6 +5479,10 @@
     "Enable features related to headless captions exploration. These are "
     "very likely unstable.";
 
+const char kEnableMediaLinkHelpersName[] = "Media Link Helpers";
+const char kEnableMediaLinkHelpersDescription[] =
+    "Enable customized per-site media link processing.";
+
 const char kEnableCrOSLiveTranslateName[] = "Live Translate CrOS";
 const char kEnableCrOSLiveTranslateDescription[] =
     "Enables the live translate feature on ChromeOS which allows for live "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index a223f6ff..5e97644 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -696,6 +696,10 @@
 extern const char kGlicPanelSetPositionOnDragDescription[];
 extern const char kGlicPanelResetOnSessionTimeoutName[];
 extern const char kGlicPanelResetOnSessionTimeoutDescription[];
+extern const char kGlicWarmingName[];
+extern const char kGlicWarmingDescription[];
+extern const char kGlicFreWarmingName[];
+extern const char kGlicFreWarmingDescription[];
 #endif  // #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 
 extern const char kClearCrossSiteCrossBrowsingContextGroupWindowNameName[];
@@ -2923,9 +2927,6 @@
 extern const char kNavBarColorAnimationName[];
 extern const char kNavBarColorAnimationDescription[];
 
-extern const char kNavBarColorMatchesTabBackgroundName[];
-extern const char kNavBarColorMatchesTabBackgroundDescription[];
-
 extern const char kNavigationCaptureRefactorAndroidName[];
 extern const char kNavigationCaptureRefactorAndroidDescription[];
 
@@ -3157,6 +3158,9 @@
 extern const char kEnableHeadlessLiveCaptionName[];
 extern const char kEnableHeadlessLiveCaptionDescription[];
 
+extern const char kEnableMediaLinkHelpersName[];
+extern const char kEnableMediaLinkHelpersDescription[];
+
 extern const char kEnableCrOSLiveTranslateName[];
 extern const char kEnableCrOSLiveTranslateDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index ff2a179..f6a91720 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -342,7 +342,6 @@
     &kMvcUpdateViewWhenModelChanged,
     &kNativePageTransitionHardwareCapture,
     &kNavBarColorAnimation,
-    &kNavBarColorMatchesTabBackground,
     &kNewTabPageAndroidTriggerForPrerender2,
     &kNotificationPermissionVariant,
     &kNotificationPermissionBottomSheet,
@@ -389,7 +388,6 @@
     &kSettingsSingleActivity,
     &kShareCustomActionsInCCT,
     &kShowCloseAllIncognitoTabsButton,
-    &kSkipIsolatedSplitPreload,
     &kSmallerTabStripTitleLimit,
     &kSuppressToolbarCapturesAtGestureEnd,
     &kSwapNewTabAndNewTabInGroupAndroid,
@@ -1103,10 +1101,6 @@
 
 BASE_FEATURE(kNavBarColorAnimation,
              "NavBarColorAnimation",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-BASE_FEATURE(kNavBarColorMatchesTabBackground,
-             "NavBarColorMatchesTabBackground",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kNewTabPageAndroidTriggerForPrerender2,
@@ -1272,10 +1266,6 @@
              "ShowCloseAllIncognitoTabsButton",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kSkipIsolatedSplitPreload,
-             "SkipIsolatedSplitPreload",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kSmallerTabStripTitleLimit,
              "SmallerTabStripTitleLimit",
              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 ea395fa..6b287c3 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -174,7 +174,6 @@
 BASE_DECLARE_FEATURE(kMvcUpdateViewWhenModelChanged);
 BASE_DECLARE_FEATURE(kNativePageTransitionHardwareCapture);
 BASE_DECLARE_FEATURE(kNavBarColorAnimation);
-BASE_DECLARE_FEATURE(kNavBarColorMatchesTabBackground);
 BASE_DECLARE_FEATURE(kNewTabPageAndroidTriggerForPrerender2);
 BASE_DECLARE_FEATURE(kNotificationPermissionVariant);
 BASE_DECLARE_FEATURE(kNotificationPermissionBottomSheet);
@@ -224,7 +223,6 @@
 BASE_DECLARE_FEATURE(kShareCustomActionsInCCT);
 BASE_DECLARE_FEATURE(kSharingHubLinkToggle);
 BASE_DECLARE_FEATURE(kShowCloseAllIncognitoTabsButton);
-BASE_DECLARE_FEATURE(kSkipIsolatedSplitPreload);
 BASE_DECLARE_FEATURE(kSmallerTabStripTitleLimit);
 BASE_DECLARE_FEATURE(kScrollToTLDOptimization);
 BASE_DECLARE_FEATURE(kSuppressToolbarCapturesAtGestureEnd);
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 cdf6e26a..75c3173 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
@@ -466,8 +466,6 @@
     public static final String NATIVE_PAGE_TRANSITION_HARDWARE_CAPTURE =
             "NativePageTransitionHardwareCapture";
     public static final String NAV_BAR_COLOR_ANIMATION = "NavBarColorAnimation";
-    public static final String NAV_BAR_COLOR_MATCHES_TAB_BACKGROUND =
-            "NavBarColorMatchesTabBackground";
     public static final String NEW_TAB_PAGE_ANDROID_TRIGGER_FOR_PRERENDER2 =
             "NewTabPageAndroidTriggerForPrerender2";
     public static final String NEW_TAB_PAGE_CUSTOMIZATION = "NewTabPageCustomization";
@@ -597,7 +595,6 @@
     public static final String SHOW_TAB_LIST_ANIMATIONS = "ShowTabListAnimations";
     public static final String SHOW_WARNINGS_FOR_SUSPICIOUS_NOTIFICATIONS =
             "ShowWarningsForSuspiciousNotifications";
-    public static final String SKIP_ISOLATED_SPLIT_PRELOAD = "SkipIsolatedSplitPreload";
     public static final String SMALLER_TAB_STRIP_TITLE_LIMIT = "SmallerTabStripTitleLimit";
     public static final String SMART_SUGGESTION_FOR_LARGE_DOWNLOADS =
             "SmartSuggestionForLargeDownloads";
@@ -933,12 +930,7 @@
                     /* defaultValue= */ false,
                     /* defaultValueInTests= */ true);
     public static final CachedFlag sNavBarColorAnimation =
-            newCachedFlag(
-                    NAV_BAR_COLOR_ANIMATION,
-                    /* defaultValue= */ false,
-                    /* defaultValueInTests= */ true);
-    public static final CachedFlag sNavBarColorMatchesTabBackground =
-            newCachedFlag(NAV_BAR_COLOR_MATCHES_TAB_BACKGROUND, true);
+            newCachedFlag(NAV_BAR_COLOR_ANIMATION, /* defaultValue= */ true);
     public static final CachedFlag sNewTabPageAndroidTriggerForPrerender2 =
             newCachedFlag(NEW_TAB_PAGE_ANDROID_TRIGGER_FOR_PRERENDER2, true);
     public static final CachedFlag sNewTabPageCustomization =
@@ -988,11 +980,6 @@
                     /* defaultValueInTests= */ true);
     public static final CachedFlag sShowHomeButtonPolicyAndroid =
             newCachedFlag(SHOW_HOME_BUTTON_POLICY_ANDROID, true);
-    public static final CachedFlag sSkipIsolatedSplitPreload =
-            newCachedFlag(
-                    SKIP_ISOLATED_SPLIT_PRELOAD,
-                    /* defaultValue= */ false,
-                    /* defaultValueInTests= */ true);
     public static final CachedFlag sSmallerTabStripTitleLimit =
             newCachedFlag(SMALLER_TAB_STRIP_TITLE_LIMIT, true);
     public static final CachedFlag sStartSurfaceReturnTime =
@@ -1150,7 +1137,6 @@
                     sMultiInstanceApplicationStatusCleanup,
                     sMvcUpdateViewWhenModelChanged,
                     sNavBarColorAnimation,
-                    sNavBarColorMatchesTabBackground,
                     sNewTabPageAndroidTriggerForPrerender2,
                     sNewTabPageCustomization,
                     sNewTabPageCustomizationForMvt,
@@ -1173,7 +1159,6 @@
                     sSearchInCCTAlternateTapHandlingIfEnabledByEmbedder,
                     sSettingsSingleActivity,
                     sShowHomeButtonPolicyAndroid,
-                    sSkipIsolatedSplitPreload,
                     sSmallerTabStripTitleLimit,
                     sStartSurfaceReturnTime,
                     sTabClosureMethodRefactor,
@@ -1615,11 +1600,6 @@
             newBooleanCachedFeatureParam(MOST_VISITED_TILES_RESELECT, "lax_query", false);
     public static final BooleanCachedFeatureParam sMostVisitedTilesReselectLaxPath =
             newBooleanCachedFeatureParam(MOST_VISITED_TILES_RESELECT, "lax_path", false);
-
-    public static final BooleanCachedFeatureParam
-            sNavBarColorMatchesTabBackgroundColorAnimationDisabled =
-                    newBooleanCachedFeatureParam(
-                            NAV_BAR_COLOR_MATCHES_TAB_BACKGROUND, "color_animation_disabled", true);
     public static final IntCachedFeatureParam sNotificationTrampolineLongJobDurationMs =
             newIntCachedFeatureParam(NOTIFICATION_TRAMPOLINE, "long_job_duration_millis", 8 * 1000);
     public static final IntCachedFeatureParam sNotificationTrampolineNormalJobDurationMs =
@@ -1772,7 +1752,6 @@
                     sMostVisitedTilesReselectLaxSchemeHost,
                     sNavBarColorAnimationDisableBottomChinColorAnimation,
                     sNavBarColorAnimationDisableEdgeToEdgeLayoutColorAnimation,
-                    sNavBarColorMatchesTabBackgroundColorAnimationDisabled,
                     sNotificationTrampolineImmediateJobDurationMs,
                     sNotificationTrampolineLongJobDurationMs,
                     sNotificationTrampolineNormalJobDurationMs,
diff --git a/chrome/browser/font_pref_change_notifier.cc b/chrome/browser/font_pref_change_notifier.cc
index d411af5..ed96ece8 100644
--- a/chrome/browser/font_pref_change_notifier.cc
+++ b/chrome/browser/font_pref_change_notifier.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/font_pref_change_notifier.h"
 
+#include "base/callback_list.h"
 #include "base/check.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/observer_list.h"
 #include "base/strings/string_util.h"
 #include "chrome/common/pref_names_util.h"
@@ -35,14 +37,14 @@
   callback_ = FontPrefChangeNotifier::Callback();
 }
 
-FontPrefChangeNotifier::FontPrefChangeNotifier(PrefService* pref_service)
-    : pref_service_(pref_service) {
-  pref_service_->AddPrefObserverAllPrefs(this);
+FontPrefChangeNotifier::FontPrefChangeNotifier(PrefService* pref_service) {
+  subscription_ =
+      pref_service->AddAllPrefsChangedCallback(base::IgnoreArgs<PrefService*>(
+          base::BindRepeating(&FontPrefChangeNotifier::OnPreferenceChanged,
+                              base::Unretained(this))));
 }
 
 FontPrefChangeNotifier::~FontPrefChangeNotifier() {
-  pref_service_->RemovePrefObserverAllPrefs(this);
-
   // There could be a shutdown race between this class and the objects
   // registered with it. We don't want the registrars to call back into us
   // when we're deleted, so tell them to unregister now.
@@ -58,8 +60,7 @@
   registrars_.RemoveObserver(registrar);
 }
 
-void FontPrefChangeNotifier::OnPreferenceChanged(PrefService* pref_service,
-                                                 std::string_view pref_name) {
+void FontPrefChangeNotifier::OnPreferenceChanged(std::string_view pref_name) {
   if (base::StartsWith(pref_name, pref_names_util::kWebKitFontPrefPrefix,
                        base::CompareCase::SENSITIVE)) {
     const std::string pref_name_string(pref_name);
diff --git a/chrome/browser/font_pref_change_notifier.h b/chrome/browser/font_pref_change_notifier.h
index 7e9410c..4eeaed5 100644
--- a/chrome/browser/font_pref_change_notifier.h
+++ b/chrome/browser/font_pref_change_notifier.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_FONT_PREF_CHANGE_NOTIFIER_H_
 #define CHROME_BROWSER_FONT_PREF_CHANGE_NOTIFIER_H_
 
+#include "base/callback_list.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/observer_list.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/prefs/pref_observer.h"
 
 class PrefService;
 
@@ -25,7 +25,7 @@
 //
 // There is one FontPrefChangeNotifier per Profile. Construct one with the
 // FontPrefChangeNotifierFactory.
-class FontPrefChangeNotifier : public PrefObserver, public KeyedService {
+class FontPrefChangeNotifier : public KeyedService {
  public:
   // The parameter is the full name of the font pref that changed.
   using Callback = base::RepeatingCallback<void(const std::string&)>;
@@ -72,11 +72,11 @@
   void AddRegistrar(Registrar* registrar);
   void RemoveRegistrar(Registrar* registrar);
 
-  // PrefObserver implementation.
-  void OnPreferenceChanged(PrefService* service,
-                           std::string_view pref_name) override;
+  // Invoked when a preference changes.
+  void OnPreferenceChanged(std::string_view pref_name);
 
-  raw_ptr<PrefService> pref_service_;  // Non-owning.
+  // Subscription for observing the PrefService.
+  base::CallbackListSubscription subscription_;
 
   // Non-owning pointers to the Registrars that have registered themselves
   // with us. We expect few registrars.
diff --git a/chrome/browser/glic/BUILD.gn b/chrome/browser/glic/BUILD.gn
index b485223..d5334ae 100644
--- a/chrome/browser/glic/BUILD.gn
+++ b/chrome/browser/glic/BUILD.gn
@@ -21,6 +21,7 @@
     "browser_ui/glic_button_controller_delegate.h",
     "browser_ui/glic_iph_controller.h",
     "browser_ui/glic_tab_indicator_helper.h",
+    "browser_ui/glic_tab_underline_view.h",
     "browser_ui/glic_vector_icon_manager.h",
     "browser_ui/scoped_glic_button_indicator.h",
     "fre/glic_fre_ui.h",
diff --git a/chrome/browser/glic/browser_ui/BUILD.gn b/chrome/browser/glic/browser_ui/BUILD.gn
index a059a4f..018d778 100644
--- a/chrome/browser/glic/browser_ui/BUILD.gn
+++ b/chrome/browser/glic/browser_ui/BUILD.gn
@@ -12,6 +12,7 @@
     "glic_button_controller.cc",
     "glic_iph_controller.cc",
     "glic_tab_indicator_helper.cc",
+    "glic_tab_underline_view.cc",
     "glic_vector_icon_manager.cc",
     "scoped_glic_button_indicator.cc",
     "theme_util.cc",
diff --git a/chrome/browser/glic/browser_ui/glic_tab_underline_view.cc b/chrome/browser/glic/browser_ui/glic_tab_underline_view.cc
new file mode 100644
index 0000000..16ea2a65
--- /dev/null
+++ b/chrome/browser/glic/browser_ui/glic_tab_underline_view.cc
@@ -0,0 +1,511 @@
+// 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 "chrome/browser/glic/browser_ui/glic_tab_underline_view.h"
+
+#include <math.h>
+
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
+#include "chrome/browser/glic/browser_ui/theme_util.h"
+#include "chrome/browser/glic/glic_keyed_service.h"
+#include "chrome/browser/glic/glic_keyed_service_factory.h"
+#include "chrome/browser/glic/host/context/glic_tab_data.h"
+#include "chrome/browser/glic/resources/grit/glic_browser_resources.h"
+#include "chrome/browser/glic/widget/glic_window_controller.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/common/chrome_features.h"
+#include "content/public/browser/context_factory.h"
+#include "content/public/browser/gpu_data_manager.h"
+#include "content/public/common/color_parser.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/view_class_properties.h"
+
+namespace glic {
+namespace {
+
+// The amount of time for the opacity to go from 0 to 1.
+constexpr static base::TimeDelta kOpacityRampUpDuration =
+    base::Milliseconds(500);
+// The amount of time for the opacity to go from 0 to 1 in a fast ramp up.
+constexpr static base::TimeDelta kFastOpacityRampUpDuration =
+    base::Milliseconds(200);
+// The amount of time for the opacity to go from 1 to 0.
+constexpr static base::TimeDelta kOpacityRampDownDuration =
+    base::Milliseconds(200);
+// The amount of time for the underline emphasis to go from 0 the max.
+constexpr static base::TimeDelta kEmphasisRampUpDuration =
+    base::Milliseconds(500);
+// The amount of time for the underline emphasis to go from max to 0.
+constexpr static base::TimeDelta kEmphasisRampDownDuration =
+    base::Milliseconds(1000);
+// The amount of time for the underline to stay emphasized.
+constexpr static base::TimeDelta kEmphasisDuration = base::Milliseconds(1500);
+// Time since creation will roll over after this time to prevent growing
+// indefinitely.
+constexpr static base::TimeDelta kMaxTime = base::Hours(1);
+
+float ClampAndInterpolate(gfx::Tween::Type type,
+                          float t,
+                          float low,
+                          float high) {
+  float clamp_lo = std::min(low, high);
+  float clamp_hi = std::max(low, high);
+  float clamped = std::clamp(t, clamp_lo, clamp_hi);
+  // Interpolate `clamped` within [low, high], using the function `type`.
+  double calculated = gfx::Tween::CalculateValue(type, clamped);
+  // Linear project `calculated` onto [low, high].
+  return gfx::Tween::FloatValueBetween(calculated, low, high);
+}
+
+int64_t TimeTicksToMicroseconds(base::TimeTicks tick) {
+  return (tick - base::TimeTicks()).InMicroseconds();
+}
+
+std::vector<SkColor> GetParameterizedColors() {
+  std::vector<SkColor> colors;
+  if (base::FeatureList::IsEnabled(features::kGlicParameterizedShader)) {
+    std::vector<std::string> unparsed_colors =
+        base::SplitString(::features::kGlicParameterizedShaderColors.Get(), "#",
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    for (const auto& unparsed : unparsed_colors) {
+      SkColor result;
+      if (!content::ParseHexColorString("#" + unparsed, &result)) {
+        return std::vector<SkColor>();
+      }
+      colors.push_back(result);
+    }
+  }
+  return colors;
+}
+
+std::vector<float> GetParameterizedFloats() {
+  std::vector<float> floats;
+  if (base::FeatureList::IsEnabled(features::kGlicParameterizedShader)) {
+    std::vector<std::string> unparsed_floats =
+        base::SplitString(::features::kGlicParameterizedShaderFloats.Get(), "#",
+                          base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    for (const auto& unparsed : unparsed_floats) {
+      double result;
+      if (!base::StringToDouble(unparsed, &result)) {
+        return std::vector<float>();
+      }
+      floats.push_back(static_cast<float>(result));
+    }
+  }
+  return floats;
+}
+
+}  // namespace
+
+GlicTabUnderlineView::GlicTabUnderlineView(Browser* browser, Tab* tab)
+    : creation_time_(base::TimeTicks::Now()),
+      colors_(GetParameterizedColors()),
+      floats_(GetParameterizedFloats()),
+      theme_service_(ThemeServiceFactory::GetForProfile(browser->GetProfile())),
+      tab_(tab),
+      browser_(browser) {
+  auto* gpu_data_manager = content::GpuDataManager::GetInstance();
+  has_hardware_acceleration_ =
+      gpu_data_manager->IsGpuRasterizationForUIEnabled();
+
+  // Upon GPU crashing, the hardware acceleration status might change. This
+  // will observe GPU changes to keep hardware acceleration status updated.
+  gpu_data_manager_observer_.Observe(gpu_data_manager);
+
+  UpdateShader();
+  CHECK(!shader_.empty()) << "Shader not initialized.";
+}
+
+GlicTabUnderlineView::~GlicTabUnderlineView() = default;
+
+void GlicTabUnderlineView::OnPaint(gfx::Canvas* canvas) {
+  if (!compositor_) {
+    return;
+  }
+  auto bounds = GetLocalBounds();
+  const auto u_resolution = GetLocalBounds();
+  // Insets aren't relevant to the tab underline effect, but are defined in the
+  // uniforms of the GlicBorderView shader.
+  gfx::Insets uniform_insets = gfx::Insets();
+
+  float corner_radius = 0.0f;
+#if BUILDFLAG(IS_MAC)
+  if (!browser_->window()->IsFullscreen()) {
+    corner_radius = 12.0f;
+  }
+#endif
+  // TODO(crbug.com/433136181): shader logic is borrowed from GlicBorderView,
+  // but emphasis can be fixed to 0 for the underline and related handling can
+  // be removed entirely.
+  std::vector<cc::PaintShader::FloatUniform> float_uniforms = {
+      {.name = SkString("u_time"), .value = GetEffectTime()},
+      {.name = SkString("u_emphasis"), .value = emphasis_},
+      {.name = SkString("u_corner_radius"), .value = corner_radius},
+      {.name = SkString("u_insets"),
+       .value = static_cast<float>(uniform_insets.left())},
+      {.name = SkString("u_progress"), .value = progress_}};
+  std::vector<cc::PaintShader::Float2Uniform> float2_uniforms = {
+      // TODO(https://crbug.com/406026829): Ideally `u_resolution` should be a
+      // vec4(x, y, w, h) and does not assume the origin is (0, 0). This way we
+      // can eliminate `u_insets` and void the shader-internal origin-padding.
+      {.name = SkString("u_resolution"),
+       .value = SkV2{static_cast<float>(u_resolution.width()),
+                     static_cast<float>(u_resolution.height())}}};
+  std::vector<cc::PaintShader::IntUniform> int_uniforms = {
+      {.name = SkString("u_dark"),
+       .value = UseDarkMode(theme_service_) ? 1 : 0}};
+
+  std::vector<cc::PaintShader::Float4Uniform> float4_uniforms;
+  if (base::FeatureList::IsEnabled(features::kGlicParameterizedShader)) {
+    for (int i = 0; i < static_cast<int>(colors_.size()); ++i) {
+      float4_uniforms.push_back(
+          {.name = SkString(absl::StrFormat("u_color%d", i + 1)),
+           .value =
+               SkV4{static_cast<float>(SkColorGetR(colors_[i]) / 255.0),
+                    static_cast<float>(SkColorGetG(colors_[i]) / 255.0),
+                    static_cast<float>(SkColorGetB(colors_[i]) / 255.0), 1.f}});
+    }
+    for (int i = 0; i < static_cast<int>(floats_.size()); ++i) {
+      float_uniforms.push_back(
+          {.name = SkString(absl::StrFormat("u_float%d", i + 1)),
+           .value = floats_[i]});
+    }
+  }
+
+  views::View::OnPaint(canvas);
+
+  cc::PaintFlags flags;
+  auto shader = cc::PaintShader::MakeSkSLCommand(
+      shader_, std::move(float_uniforms), std::move(float2_uniforms),
+      std::move(float4_uniforms), std::move(int_uniforms),
+      cached_paint_shader_);
+
+  flags.setShader(shader);
+
+  if (base::FeatureList::IsEnabled(features::kGlicUseShaderCache)) {
+    cached_paint_shader_ = shader;
+  }
+
+  constexpr static int kMaxEffectWidth = 2;
+  gfx::Point origin =
+      bounds.origin() +
+      gfx::Vector2d(0, bounds.size().height() - kMaxEffectWidth);
+  gfx::Size size(bounds.size().width(), kMaxEffectWidth);
+  gfx::Rect effect_bounds(origin, size);
+  canvas->DrawRect(gfx::RectF(effect_bounds), flags);
+}
+
+void GlicTabUnderlineView::OnAnimationStep(base::TimeTicks timestamp) {
+  last_animation_step_time_ = timestamp;
+  if (first_frame_time_.is_null()) {
+    first_frame_time_ = timestamp;
+  }
+  if (first_emphasis_frame_.is_null()) {
+    first_emphasis_frame_ = timestamp;
+
+    // The time gaps when the underline is in steady state cause discontinuous
+    // underline states when switching tabs. By keeping track of the total
+    // steady time, we can have a continuous effect time. Each steady time
+    // interval is added to the total at the very beginning of an upcoming
+    // emphasis animation. Note: the opacity ramp up / down is not part of the
+    // shader animation.
+    if (!last_emphasis_frame_.is_null()) {
+      total_steady_time_ += timestamp - last_emphasis_frame_;
+      last_emphasis_frame_ = base::TimeTicks{};
+    }
+  }
+  if (record_first_ramp_down_frame_) {
+    record_first_ramp_down_frame_ = false;
+    first_ramp_down_frame_ = timestamp;
+  }
+
+  base::TimeDelta emphasis_since_first_frame =
+      timestamp - first_emphasis_frame_;
+  emphasis_ = GetEmphasis(emphasis_since_first_frame);
+  base::TimeDelta opacity_since_first_frame = timestamp - first_frame_time_;
+  opacity_ = GetOpacity(timestamp);
+  progress_ = GetEffectProgress(timestamp);
+
+  // TODO(liuwilliam): Ideally this should be done in paint-related methods.
+  // Consider moving it to LayerDelegate::OnPaintLayer().
+  CHECK(layer());
+  layer()->SetOpacity(opacity_);
+
+  // Don't animate if the animations have exhausted and we haven't started
+  // ramping down. We shouldn't be an observer for more than 60 seconds
+  // (CompositorAnimationObserver::NotifyFailure()).
+  bool emphasis_done =
+      emphasis_ == 0.f && !emphasis_since_first_frame.is_zero();
+  bool opacity_ramp_up_done =
+      opacity_ == 1.f && !opacity_since_first_frame.is_zero();
+  bool show_steady_state =
+      emphasis_done && opacity_ramp_up_done && first_ramp_down_frame_.is_null();
+
+  if (show_steady_state) {
+    // If skipping the animation the class does not need to be an animation
+    // observer.
+    compositor_->RemoveAnimationObserver(this);
+    if (last_emphasis_frame_.is_null()) {
+      last_emphasis_frame_ = timestamp;
+    }
+    return;
+  }
+
+  bool opacity_ramp_down_done =
+      opacity_ == 0.f && !first_ramp_down_frame_.is_null();
+  if (opacity_ramp_down_done) {
+    StopShowing();
+    return;
+  }
+
+  SchedulePaint();
+}
+
+void GlicTabUnderlineView::OnCompositingShuttingDown(
+    ui::Compositor* compositor) {
+  StopShowing();
+}
+
+void GlicTabUnderlineView::OnGpuInfoUpdate() {
+  auto* gpu_data_manager = content::GpuDataManager::GetInstance();
+  bool has_hardware_acceleration =
+      gpu_data_manager->IsGpuRasterizationForUIEnabled();
+
+  if (has_hardware_acceleration_ != has_hardware_acceleration) {
+    has_hardware_acceleration_ = has_hardware_acceleration;
+    UpdateShader();
+
+    if (IsShowing()) {
+      SchedulePaint();
+    }
+  }
+}
+
+bool GlicTabUnderlineView::IsShowing() const {
+  // `compositor_` is set when the underline starts to show and unset when the
+  // underline stops to show.
+  return !!compositor_;
+}
+
+void GlicTabUnderlineView::Show() {
+  if (compositor_) {
+    // The user can click on the glic icon after the window is shown. The
+    // animation is already playing at that time.
+    return;
+  }
+
+  if (!parent()) {
+    base::debug::DumpWithoutCrashing();
+    return;
+  }
+
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+  SetVisible(true);
+
+  skip_emphasis_animation_ =
+      gfx::Animation::PrefersReducedMotion() || ForceSimplifiedShader();
+
+  ui::Compositor* compositor = layer()->GetCompositor();
+  if (!compositor) {
+    base::debug::DumpWithoutCrashing();
+    return;
+  }
+
+  compositor_ = compositor;
+  compositor_animation_observation_.Observe(compositor_.get());
+  compositor_observation_.Observe(compositor_.get());
+}
+
+void GlicTabUnderlineView::StopShowing() {
+  if (!compositor_) {
+    return;
+  }
+
+  compositor_observation_.Reset();
+  compositor_animation_observation_.Reset();
+  compositor_ = nullptr;
+  first_frame_time_ = base::TimeTicks{};
+  first_emphasis_frame_ = base::TimeTicks{};
+  last_emphasis_frame_ = base::TimeTicks{};
+  first_ramp_down_frame_ = base::TimeTicks{};
+  record_first_ramp_down_frame_ = false;
+  total_steady_time_ = base::Milliseconds(0);
+  opacity_ = 0.f;
+  emphasis_ = 0.f;
+
+  // `DestroyLayer()` schedules another paint to repaint the affected area by
+  // the destroyed layer.
+  DestroyLayer();
+  SetVisible(false);
+}
+
+float GlicTabUnderlineView::GetEmphasis(base::TimeDelta delta) const {
+  if (skip_emphasis_animation_) {
+    return 0.f;
+  }
+  static constexpr base::TimeDelta kRampUpAndSteady =
+      kEmphasisRampUpDuration + kEmphasisDuration;
+  if (delta < kRampUpAndSteady) {
+    auto target = static_cast<float>(delta / kEmphasisRampUpDuration);
+    return ClampAndInterpolate(gfx::Tween::Type::EASE_OUT, target, 0, 1);
+  }
+  auto target = static_cast<float>((delta - kRampUpAndSteady) /
+                                   kEmphasisRampDownDuration);
+  return ClampAndInterpolate(gfx::Tween::Type::EASE_IN_OUT_2, target, 1, 0);
+}
+
+void GlicTabUnderlineView::ResetEmphasisAndReplay() {
+  // TOOD(crbug.com/398319435): Remove once we know why this is called before
+  // `Show()`.
+  if (!compositor_) {
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "opacity", opacity_);
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "emphasis", emphasis_);
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "creation",
+                            TimeTicksToMicroseconds(creation_time_));
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "first_frame",
+                            TimeTicksToMicroseconds(first_frame_time_));
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "first_emphasis",
+                            TimeTicksToMicroseconds(first_emphasis_frame_));
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "last_step",
+                            TimeTicksToMicroseconds(last_animation_step_time_));
+    SCOPED_CRASH_KEY_NUMBER("crbug-398319435", "first_rampdown",
+                            TimeTicksToMicroseconds(first_ramp_down_frame_));
+    base::debug::DumpWithoutCrashing();
+
+    // Gracefully handling the crash case in crbug.com/398319435 by
+    // closing(minimizing) the glic window.
+    // TODO(crbug.com/413442838): Add tests to reproduce the dump without crash
+    // and validate the solution.
+    GetGlicService()->window_controller().Close();
+    return;
+  }
+  CHECK(compositor_->HasObserver(this));
+  if (!compositor_->HasAnimationObserver(this)) {
+    compositor_->AddAnimationObserver(this);
+  }
+  first_emphasis_frame_ = base::TimeTicks{};
+  SchedulePaint();
+}
+
+float GlicTabUnderlineView::GetOpacity(base::TimeTicks timestamp) {
+  auto ramp_up_duration = skip_emphasis_animation_ ? kFastOpacityRampUpDuration
+                                                   : kOpacityRampUpDuration;
+  if (!first_ramp_down_frame_.is_null()) {
+    // The ramp up opacity could be any value between 0-1 during the ramp up
+    // time. Thus, the ramping down opacity must be deducted from the value of
+    // ramp up opacity at the time of `first_ramp_down_frame_`.
+    base::TimeDelta delta = first_ramp_down_frame_ - first_frame_time_;
+    float ramp_up_opacity =
+        std::clamp(static_cast<float>(delta.InMillisecondsF() /
+                                      ramp_up_duration.InMillisecondsF()),
+                   0.0f, 1.0f);
+
+    base::TimeDelta time_since_first_ramp_down_frame =
+        timestamp - first_ramp_down_frame_;
+    float ramp_down_opacity =
+        static_cast<float>(time_since_first_ramp_down_frame.InMillisecondsF() /
+                           kOpacityRampDownDuration.InMillisecondsF());
+    ramp_down_opacity_ =
+        std::clamp(ramp_up_opacity - ramp_down_opacity, 0.0f, 1.0f);
+    return ramp_down_opacity_;
+  } else {
+    base::TimeDelta time_since_first_frame = timestamp - first_frame_time_;
+    return std::clamp(
+        static_cast<float>(ramp_down_opacity_ +
+                           (time_since_first_frame.InMillisecondsF() /
+                            ramp_up_duration.InMillisecondsF())),
+        0.0f, 1.0f);
+  }
+}
+
+void GlicTabUnderlineView::StartRampingDown() {
+  CHECK(compositor_);
+
+  // From now on the opacity will be decreased until it reaches 0.
+  record_first_ramp_down_frame_ = true;
+
+  if (!compositor_->HasAnimationObserver(this)) {
+    compositor_->AddAnimationObserver(this);
+  }
+}
+
+float GlicTabUnderlineView::GetEffectTime() const {
+  if (last_animation_step_time_.is_null()) {
+    return 0;
+  }
+
+  // Returns a constant duration so the underline states don't jump around when
+  // switching tabs.
+  if (skip_emphasis_animation_) {
+    auto time_since_creation = (first_frame_time_ - creation_time_) % kMaxTime;
+    return time_since_creation.InSecondsF();
+  }
+
+  auto time_since_creation =
+      ((last_animation_step_time_ - creation_time_) - total_steady_time_) %
+      kMaxTime;
+  return time_since_creation.InSecondsF();
+}
+
+float GlicTabUnderlineView::GetEffectProgress(base::TimeTicks timestamp) const {
+  if (skip_emphasis_animation_) {
+    return 0.0;
+  }
+  base::TimeDelta time_since_first_frame = timestamp - first_emphasis_frame_;
+  base::TimeDelta total_duration =
+      kEmphasisRampUpDuration + kEmphasisRampDownDuration + kEmphasisDuration;
+  return std::clamp(
+      static_cast<float>(time_since_first_frame.InMillisecondsF() /
+                         total_duration.InMillisecondsF()),
+      0.0f, 1.0f);
+}
+
+bool GlicTabUnderlineView::ForceSimplifiedShader() const {
+  return base::FeatureList::IsEnabled(features::kGlicForceSimplifiedBorder) ||
+         !has_hardware_acceleration_;
+}
+
+GlicKeyedService* GlicTabUnderlineView::GetGlicService() const {
+  auto* service =
+      GlicKeyedServiceFactory::GetGlicKeyedService(browser_->GetProfile());
+  CHECK(service);
+  return service;
+}
+
+void GlicTabUnderlineView::UpdateShader() {
+  if (base::FeatureList::IsEnabled(features::kGlicParameterizedShader) &&
+      !colors_.empty() && !floats_.empty()) {
+    shader_ =
+        ForceSimplifiedShader()
+            ? ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+                  IDR_GLIC_SIMPLIFIED_PARAMETERIZED_BORDER_SHADER)
+            : ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+                  IDR_GLIC_PARAMETERIZED_BORDER_SHADER);
+  } else {
+    shader_ =
+        ForceSimplifiedShader()
+            ? ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+                  IDR_GLIC_SIMPLIFIED_BORDER_SHADER)
+            : ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+                  IDR_GLIC_BORDER_SHADER);
+  }
+}
+
+BEGIN_METADATA(GlicTabUnderlineView)
+END_METADATA
+
+}  // namespace glic
diff --git a/chrome/browser/glic/browser_ui/glic_tab_underline_view.h b/chrome/browser/glic/browser_ui/glic_tab_underline_view.h
new file mode 100644
index 0000000..ffb132b
--- /dev/null
+++ b/chrome/browser/glic/browser_ui/glic_tab_underline_view.h
@@ -0,0 +1,145 @@
+// 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 CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_TAB_UNDERLINE_VIEW_H_
+#define CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_TAB_UNDERLINE_VIEW_H_
+
+#include "base/scoped_observation.h"
+#include "cc/paint/paint_shader.h"
+#include "content/public/browser/gpu_data_manager_observer.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/compositor/compositor_animation_observer.h"
+#include "ui/compositor/compositor_observer.h"
+#include "ui/views/metadata/view_factory.h"
+#include "ui/views/view.h"
+
+class Browser;
+class Tab;
+class ThemeService;
+
+namespace gfx {
+class Canvas;
+}  // namespace gfx
+
+namespace content {
+class GpuDataManager;
+}  // namespace content
+
+namespace glic {
+
+class GlicKeyedService;
+
+// TODO(crbug.com/433273615): Share animation code with GlicBorderView to
+// de-duplicate implementation.
+class GlicTabUnderlineView : public views::View,
+                             public ui::CompositorAnimationObserver,
+                             public ui::CompositorObserver,
+                             public content::GpuDataManagerObserver {
+  METADATA_HEADER(GlicTabUnderlineView, views::View)
+
+ public:
+  explicit GlicTabUnderlineView(Browser* browser, Tab* tab);
+  GlicTabUnderlineView(const GlicTabUnderlineView&) = delete;
+  GlicTabUnderlineView& operator=(const GlicTabUnderlineView&) = delete;
+  ~GlicTabUnderlineView() override;
+
+  // `views::View`:
+  void OnPaint(gfx::Canvas* canvas) override;
+
+  // `ui::CompositorAnimationObserver`:
+  void OnAnimationStep(base::TimeTicks timestamp) override;
+
+  // `ui::CompositorObserver`:
+  void OnCompositingShuttingDown(ui::Compositor* compositor) override;
+
+  // `content::GpuDataManagerObserver`:
+  void OnGpuInfoUpdate() override;
+
+  bool IsShowing() const;
+
+ private:
+  void Show();
+  void StopShowing();
+
+  // A value from 0 to 1 indicating how much the underline is to be emphasized.
+  float GetEmphasis(base::TimeDelta delta) const;
+
+  // Only valid to call after the animation has started.
+  void ResetEmphasisAndReplay();
+
+  // A value from 0 to 1 indicating the opacity of the underline.
+  float GetOpacity(base::TimeTicks timestamp);
+
+  // Sets the necessary bits to start ramping down the opacity once it's called.
+  void StartRampingDown();
+
+  // Returns the effect evolution time; wraps after an hour.
+  float GetEffectTime() const;
+
+  // Returns a value from 0 to 1 indicating progress through the effect.
+  float GetEffectProgress(base::TimeTicks timestamp) const;
+
+  bool ForceSimplifiedShader() const;
+
+  GlicKeyedService* GetGlicService() const;
+
+  void UpdateShader();
+
+  std::string shader_;
+
+  // When it is true, the class directly presents a static underline and when it
+  // is false, it animates the underline first.
+  // TODO(crbug.com/433136761): Implement a simplified underline with clearer
+  // difference in motion.
+  bool skip_emphasis_animation_ = false;
+
+  float opacity_ = 0.f;
+  float emphasis_ = 0.f;
+  float progress_ = 0.f;
+
+  const base::TimeTicks creation_time_;
+  base::TimeTicks first_frame_time_;
+  base::TimeTicks first_emphasis_frame_;
+  base::TimeTicks last_emphasis_frame_;
+  base::TimeTicks last_animation_step_time_;
+  base::TimeDelta total_steady_time_;
+
+  bool record_first_ramp_down_frame_ = false;
+  base::TimeTicks first_ramp_down_frame_;
+  // See crbug.com/407106595: Allows the underline animation to play seamlessly
+  // when the browser UI has lost focus temporarily.
+  // TODO(crbug.com/408210785): Add a test for this case.
+  float ramp_down_opacity_ = 0.f;
+
+  bool has_hardware_acceleration_ = false;
+  base::ScopedObservation<content::GpuDataManager,
+                          content::GpuDataManagerObserver>
+      gpu_data_manager_observer_{this};
+
+  base::ScopedObservation<ui::Compositor, ui::CompositorObserver>
+      compositor_observation_{this};
+  base::ScopedObservation<ui::Compositor, ui::CompositorAnimationObserver>
+      compositor_animation_observation_{this};
+
+  sk_sp<cc::PaintShader> cached_paint_shader_;
+
+  const std::vector<SkColor> colors_;
+  const std::vector<float> floats_;
+
+  raw_ptr<ui::Compositor> compositor_ = nullptr;
+  raw_ptr<ThemeService> theme_service_ = nullptr;
+  raw_ptr<Tab> tab_ = nullptr;
+  raw_ptr<Browser> browser_ = nullptr;
+};
+
+BEGIN_VIEW_BUILDER(, GlicTabUnderlineView, views::View)
+VIEW_BUILDER_PROPERTY(bool, Visible)
+VIEW_BUILDER_PROPERTY(bool, CanProcessEventsWithinSubtree)
+END_VIEW_BUILDER
+
+}  // namespace glic
+
+DEFINE_VIEW_BUILDER(, glic::GlicTabUnderlineView)
+
+#endif  // CHROME_BROWSER_GLIC_BROWSER_UI_GLIC_TAB_UNDERLINE_VIEW_H_
diff --git a/chrome/browser/glic/glic_profile_manager.cc b/chrome/browser/glic/glic_profile_manager.cc
index 54fb4ad..a2800b6d1 100644
--- a/chrome/browser/glic/glic_profile_manager.cc
+++ b/chrome/browser/glic/glic_profile_manager.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
 #include "chrome/browser/ui/profiles/profile_picker.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #include "chrome/common/chrome_features.h"
@@ -85,9 +85,10 @@
   }
 
   // Look for a profile to based on most recently used browser windows
-  for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
-    if (GlicEnabling::IsEnabledAndConsentForProfile(browser->profile())) {
-      return browser->profile();
+  for (BrowserWindowInterface* browser :
+       GetBrowserWindowInterfacesOrderedByActivation()) {
+    if (GlicEnabling::IsEnabledAndConsentForProfile(browser->GetProfile())) {
+      return browser->GetProfile();
     }
   }
 
diff --git a/chrome/browser/glic/glic_zero_state_suggestions_manager.cc b/chrome/browser/glic/glic_zero_state_suggestions_manager.cc
index 97a6550..44f39b6 100644
--- a/chrome/browser/glic/glic_zero_state_suggestions_manager.cc
+++ b/chrome/browser/glic/glic_zero_state_suggestions_manager.cc
@@ -40,18 +40,18 @@
 GlicZeroStateSuggestionsManager::~GlicZeroStateSuggestionsManager() = default;
 
 void GlicZeroStateSuggestionsManager::
-    NotifyZeroStateSuggestionsOnFocusedTabChanged(
+    NotifyZeroStateSuggestionsOnFocusedTabDataChanged(
         bool is_first_run,
         const std::vector<std::string>& supported_tools,
-        const FocusedTabData& focused_tab_data) {
+        const mojom::TabData* focused_tab_data) {
   if (!window_controller_->IsShowing()) {
     return;
   }
 
-  content::WebContents* active_web_contents = nullptr;
-  if (focused_tab_data.GetFocus().has_value()) {
-    active_web_contents = focused_tab_data.GetFocus().value()->GetContents();
-  }
+  content::WebContents* active_web_contents =
+      sharing_manager_->GetFocusedTabData().focus()
+          ? sharing_manager_->GetFocusedTabData().focus()->GetContents()
+          : nullptr;
 
   if (contextual_cueing_service_ && active_web_contents) {
     // Notify host that suggestions are pending.
@@ -122,10 +122,12 @@
     }
     // If there were previous subscriptions they will be unsubscribed when the
     // old values are destructed on assignment.
+    // TODO: b/433738020 - Investigate whether we should listen to a different
+    // callback.
     current_zero_state_suggestions_focus_change_subscription_ =
-        sharing_manager_->AddFocusedTabChangedCallback(base::BindRepeating(
+        sharing_manager_->AddFocusedTabDataChangedCallback(base::BindRepeating(
             &GlicZeroStateSuggestionsManager::
-                NotifyZeroStateSuggestionsOnFocusedTabChanged,
+                NotifyZeroStateSuggestionsOnFocusedTabDataChanged,
             GetWeakPtr(), is_first_run, supported_tools));
     current_zero_state_suggestions_pinned_tab_change_subscription_ =
         sharing_manager_->AddPinnedTabsChangedCallback(base::BindRepeating(
diff --git a/chrome/browser/glic/glic_zero_state_suggestions_manager.h b/chrome/browser/glic/glic_zero_state_suggestions_manager.h
index 9d2e9b3..21adf347 100644
--- a/chrome/browser/glic/glic_zero_state_suggestions_manager.h
+++ b/chrome/browser/glic/glic_zero_state_suggestions_manager.h
@@ -31,10 +31,10 @@
   virtual ~GlicZeroStateSuggestionsManager();
 
   // Callback to send zero state suggestions to the webui on tab changes.
-  void NotifyZeroStateSuggestionsOnFocusedTabChanged(
+  void NotifyZeroStateSuggestionsOnFocusedTabDataChanged(
       bool is_first_run,
       const std::vector<std::string>& supported_tools,
-      const glic::FocusedTabData& focused_tab_data);
+      const mojom::TabData* focused_tab_data);
 
   // Callback to send zero state suggestions to the webui on pinned tab changes.
   void NotifyZeroStateSuggestionsOnPinnedTabChanged(
diff --git a/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc b/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
index 871bf44..710367d 100644
--- a/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
+++ b/chrome/browser/glic/host/context/glic_sharing_manager_impl.cc
@@ -108,12 +108,6 @@
     tabs::TabHandle tab_handle,
     const mojom::GetTabContextOptions& options,
     base::OnceCallback<void(mojom::GetContextResultPtr)> callback) {
-  if (!profile_->GetPrefs()->GetBoolean(prefs::kGlicTabContextEnabled) ||
-      !window_controller_->IsShowing()) {
-    std::move(callback).Run(mojom::GetContextResult::NewErrorReason(
-        std::string("permission denied")));
-    return;
-  }
 
   auto* tab = tab_handle.Get();
   if (!tab) {
@@ -122,8 +116,18 @@
     return;
   }
 
-  const bool is_focused = focused_tab_manager_.IsTabFocused(tab_handle);
   const bool is_pinned = pinned_tab_manager_.IsTabPinned(tab_handle);
+
+  if ((!profile_->GetPrefs()->GetBoolean(prefs::kGlicTabContextEnabled) ||
+      !window_controller_->IsShowing()) && !is_pinned) {
+    std::move(callback).Run(mojom::GetContextResult::NewErrorReason(
+        std::string("permission denied")));
+    return;
+  }
+
+
+
+  const bool is_focused = focused_tab_manager_.IsTabFocused(tab_handle);
   const bool is_shared = is_focused || is_pinned;
   if (!is_shared || !IsValidCandidateForSharing(tab->GetContents())) {
     std::move(callback).Run(mojom::GetContextResult::NewErrorReason(
@@ -138,6 +142,20 @@
   FetchPageContext(tab, options, std::move(callback));
 }
 
+void GlicSharingManagerImpl::GetContextForActorFromTab(
+    tabs::TabHandle tab_handle,
+    const mojom::GetTabContextOptions& options,
+    base::OnceCallback<void(mojom::GetContextResultPtr)> callback) {
+  auto* tab = tab_handle.Get();
+  if (!tab) {
+    std::move(callback).Run(
+        mojom::GetContextResult::NewErrorReason(std::string("tab not found")));
+    return;
+  }
+
+  FetchPageContext(tab, options, std::move(callback));
+}
+
 bool GlicSharingManagerImpl::IsBrowserValidForSharing(
     BrowserWindowInterface* browser_interface) {
   if (!browser_interface) {
diff --git a/chrome/browser/glic/host/context/glic_sharing_manager_impl.h b/chrome/browser/glic/host/context/glic_sharing_manager_impl.h
index 86c1c43..5b740b53 100644
--- a/chrome/browser/glic/host/context/glic_sharing_manager_impl.h
+++ b/chrome/browser/glic/host/context/glic_sharing_manager_impl.h
@@ -90,6 +90,11 @@
       const mojom::GetTabContextOptions& options,
       base::OnceCallback<void(mojom::GetContextResultPtr)> callback);
 
+  void GetContextForActorFromTab(
+      tabs::TabHandle tab_handle,
+      const mojom::GetTabContextOptions& options,
+      base::OnceCallback<void(mojom::GetContextResultPtr)> callback);
+
   // True if the immutable attributes of `browser` are valid for Glic focus.
   // or pinning. Invalid browsers are never observed.
   bool IsBrowserValidForSharing(
diff --git a/chrome/browser/glic/host/glic.mojom b/chrome/browser/glic/host/glic.mojom
index fd12c39..b79a97b 100644
--- a/chrome/browser/glic/host/glic.mojom
+++ b/chrome/browser/glic/host/glic.mojom
@@ -175,6 +175,17 @@
 
 // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:ActInFocusedTabErrorReason)
 
+// The state of an actor task. This MUST be kept in sync with the glic_api.ts
+// enum.
+[Stable, Extensible]
+enum ActorTaskState {
+  [Default] kUnknown = 0,
+  kIdle = 1,
+  kActing = 2,
+  kPaused = 3,
+  kStopped = 4,
+};
+
 // Reason why capturing desktop screenshot failed. This MUST be kept in sync
 // with the glic_api.ts enum.
 [Stable, Extensible]
@@ -252,6 +263,8 @@
   bool enable_maybe_refresh_user_status;
   // Whether multi tab is enabled.
   bool enable_multi_tab;
+  // Whether get context for actor from tab is enabled.
+  bool enable_get_context_actor;
   // The list of capabilities of the host.
   array<HostCapability> host_capabilities;
 };
@@ -497,6 +510,12 @@
   GetContextFromTab(int32 tab_id, GetTabContextOptions options)
       => (GetContextResult result);
 
+  // Returns the context from the tab associated with `tab_id` for an actor.
+  // This skips the focus check.
+  [RuntimeFeature=glic.mojom.features.kGlicActorTabContext]
+  GetContextForActorFromTab(int32 tab_id, GetTabContextOptions options)
+      => (GetContextResult result);
+
   // Sets the maximum number of supported pinned tabs. Negative means that the
   // client has no limit. Since the browser may only support so many, the
   // effective limit is returned. The returned number may also differ from the
@@ -901,6 +920,10 @@
   NotifyZeroStateSuggestionsChanged(
     ZeroStateSuggestionsV2? suggestions,
     ZeroStateSuggestionsOptions options);
+
+  // Notify that the actor task with the given id has changed to the indicated
+  // state.
+  NotifyActorTaskStateChanged(int32 task_id, ActorTaskState state);
 };
 
 // Information extracted from a tab.
diff --git a/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc b/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc
index 688026e..fea9e754 100644
--- a/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc
+++ b/chrome/browser/glic/host/glic_actor_controller_interactive_uitest.cc
@@ -445,6 +445,23 @@
         expected)));
   }
 
+  auto WaitForActorTaskState(mojom::ActorTaskState expected_state) {
+    return Steps(InAnyContext(WithElement(
+        kGlicContentsElementId,
+        [&task_id = task_id_, expected_state](ui::TrackedElement* el) {
+          content::WebContents* glic_contents =
+              AsInstrumentedWebContents(el)->web_contents();
+          std::string script = content::JsReplace(
+              R"js(
+              client.browser.getActorTaskState($1).waitUntil((state) => {
+                return state == $2;
+              });
+              )js",
+              task_id.value(), base::to_underlying(expected_state));
+          ASSERT_TRUE(content::ExecJs(glic_contents, script));
+        })));
+  }
+
   // Returns a callback that returns the given string as the action proto. Meant
   // for testing error handling since this allows providing an invalid proto.
   ActionProtoProvider ArbitraryStringProvider(std::string_view str) {
@@ -913,7 +930,8 @@
   );
 }
 
-IN_PROC_BROWSER_TEST_F(GlicActorControllerUiTest, PauseThenStopActorTask) {
+IN_PROC_BROWSER_TEST_F(GlicActorControllerUiTest,
+                       DISABLED_PauseThenStopActorTask) {
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kNewActorTabId);
   constexpr std::string_view kClickableButtonLabel = "clickable";
 
@@ -928,12 +946,15 @@
     GetPageContextFromFocusedTab(),
     ClickAction(kClickableButtonLabel),
     WaitForJsResult(kNewActorTabId, "() => button_clicked"),
+    WaitForActorTaskState(mojom::ActorTaskState::kIdle),
 
     PauseActorTask(),
     CheckIsActingOnTab(kNewActorTabId, true),
+    WaitForActorTaskState(mojom::ActorTaskState::kPaused),
 
     StopActorTask(),
-    CheckIsActingOnTab(kNewActorTabId, false)
+    CheckIsActingOnTab(kNewActorTabId, false),
+    WaitForActorTaskState(mojom::ActorTaskState::kStopped)
       // clang-format on
   );
 }
diff --git a/chrome/browser/glic/host/glic_api_browsertest.cc b/chrome/browser/glic/host/glic_api_browsertest.cc
index 5a10327..33cc075 100644
--- a/chrome/browser/glic/host/glic_api_browsertest.cc
+++ b/chrome/browser/glic/host/glic_api_browsertest.cc
@@ -87,7 +87,7 @@
 
 namespace glic {
 namespace {
-using ::base::test::RunOnceCallback;
+using ::base::test::RunOnceCallbackRepeatedly;
 using testing::_;
 using testing::Contains;
 using testing::Pair;
@@ -968,9 +968,13 @@
   // Navigate to another page in the existing tab.
   std::vector<std::string> suggestions = {"suggestion1", "suggestion2",
                                           "suggestion3"};
+  // This gets called once for the primary page change and once for the title
+  // change. This is fine. In the actual cueing service implementation, it
+  // coalesces the calls for the same page if there is already an existing
+  // request for the page in flight.
   EXPECT_CALL(*mock_cueing_service(),
               GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(suggestions));
+      .WillRepeatedly(RunOnceCallbackRepeatedly<3>(suggestions));
   RunTestSequence(NavigateWebContents(
       kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
                      "/scrollable_page_with_content.html")));
@@ -1102,6 +1106,11 @@
   ExecuteJsTest();
 }
 
+IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab,
+                       testGetContextForActorFromFocusedTabWithoutPermission) {
+  ExecuteJsTest();
+}
+
 #if BUILDFLAG(ENABLE_PDF)
 #define MAYBE_testGetContextFromFocusedTabWithPdfFile \
   testGetContextFromFocusedTabWithPdfFile
diff --git a/chrome/browser/glic/host/glic_features.mojom b/chrome/browser/glic/host/glic_features.mojom
index 09a6635..355de846 100644
--- a/chrome/browser/glic/host/glic_features.mojom
+++ b/chrome/browser/glic/host/glic_features.mojom
@@ -10,6 +10,12 @@
   const bool default_state = false;
 };
 
+// Allows actor code to get tab context.
+feature kGlicActorTabContext {
+  const string name = "GlicActorTabContext";
+  const bool default_state = true;
+};
+
 feature kZeroStateSuggestionsV2 {
   const string name = "ZeroStateSuggestionsV2";
   const bool default_state = false;
diff --git a/chrome/browser/glic/host/glic_page_handler.cc b/chrome/browser/glic/host/glic_page_handler.cc
index cce9d1e8..99cf82b 100644
--- a/chrome/browser/glic/host/glic_page_handler.cc
+++ b/chrome/browser/glic/host/glic_page_handler.cc
@@ -21,6 +21,7 @@
 #include "base/uuid.h"
 #include "base/version_info/version_info.h"
 #include "chrome/browser/actor/actor_keyed_service.h"
+#include "chrome/browser/actor/actor_task.h"
 #include "chrome/browser/actor/aggregated_journal.h"
 #include "chrome/browser/actor/aggregated_journal_in_memory_serializer.h"
 #include "chrome/browser/actor/task_id.h"
@@ -46,6 +47,7 @@
 #include "chrome/browser/glic/host/glic_synthetic_trial_manager.h"
 #include "chrome/browser/glic/host/glic_web_client_access.h"
 #include "chrome/browser/glic/host/host.h"
+#include "chrome/browser/glic/media/glic_media_link_helper.h"
 #include "chrome/browser/glic/widget/browser_conditions.h"
 #include "chrome/browser/glic/widget/glic_window_controller.h"
 #include "chrome/browser/global_features.h"
@@ -54,6 +56,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/common/chrome_features.h"
@@ -69,6 +72,7 @@
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
+#include "media/base/media_switches.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "pdf/buildflags.h"
@@ -400,13 +404,23 @@
 
     // TODO(b/430054430): Fetch and include system data to the feedback.
     feedback_data->set_description(
-        reason + "\n\n" + base::Uuid::GenerateRandomV4().AsLowercaseString());
+        reason + " - " + base::Uuid::GenerateRandomV4().AsLowercaseString());
     feedback_data->set_product_id(feedback::kGeminiWebProductId);
     feedback_data->set_category_tag(
         std::string(feedback::kGeminiWebJournalCategoryTag));
     feedback_data->set_is_offensive_or_unsafe(false);
     feedback_data->AddFile("actor-journal", journal);
 
+    signin::IdentityManager* identity_manager =
+        IdentityManagerFactory::GetForProfile(
+            actor_keyed_service_->GetProfile());
+    if (identity_manager &&
+        identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
+      feedback_data->set_user_email(
+          identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin)
+              .email);
+    }
+
     feedback_data->CompressSystemInfo();
     feedback_data->OnFeedbackPageDataComplete();
   }
@@ -527,6 +541,15 @@
             &GlicWebClientHandler::OnOsPermissionSettingChanged,
             base::Unretained(this)));
 
+    if (base::FeatureList::IsEnabled(features::kGlicActor)) {
+      if (auto* actor_service = actor::ActorKeyedService::Get(profile_)) {
+        actor_task_state_changed_subscription_ =
+            actor_service->AddTaskStateChangedCallback(base::BindRepeating(
+                &GlicWebClientHandler::NotifyActorTaskStateChanged,
+                base::Unretained(this)));
+      }
+    }
+
     auto state = glic::mojom::WebClientInitialState::New();
     state->chrome_version = version_info::GetVersion();
     state->microphone_permission_enabled =
@@ -587,6 +610,8 @@
         features::kGlicUserStatusRefreshApi.Get();
     state->enable_multi_tab =
         base::FeatureList::IsEnabled(glic::mojom::features::kGlicMultiTab);
+    state->enable_get_context_actor = base::FeatureList::IsEnabled(
+        glic::mojom::features::kGlicActorTabContext);
 #if BUILDFLAG(ENABLE_PDF)
     if (features::kGlicScrollToPDF.Get()) {
       state->host_capabilities.push_back(mojom::HostCapability::kScrollToPdf);
@@ -639,6 +664,18 @@
       std::move(callback).Run(nullptr);
       return;
     }
+    if (base::FeatureList::IsEnabled(media::kMediaLinkHelpers)) {
+      if (auto* tab = glic_sharing_manager_->GetFocusedTabData().focus()) {
+        const bool replaced =
+            GlicMediaLinkHelper(tab->GetContents()).MaybeReplaceNavigation(url);
+        base::UmaHistogramBoolean("Glic.MaybeReplaceNavigation.Result",
+                                  replaced);
+        if (replaced) {
+          std::move(callback).Run(nullptr);
+          return;
+        }
+      }
+    }
     glic_service_->CreateTab(url, open_in_background, window_id,
                              std::move(callback));
   }
@@ -724,6 +761,14 @@
                                              std::move(callback));
   }
 
+  void GetContextForActorFromTab(
+      int32_t tab_id,
+      glic::mojom::GetTabContextOptionsPtr options,
+      GetContextForActorFromTabCallback callback) override {
+    glic_sharing_manager_->GetContextForActorFromTab(
+        tabs::TabHandle(tab_id), *options, std::move(callback));
+  }
+
   void SetMaximumNumberOfPinnedTabs(
       uint32_t num_tabs,
       SetMaximumNumberOfPinnedTabsCallback callback) override {
@@ -1340,6 +1385,23 @@
     web_client_->NotifyFocusedTabChanged(std::move(data));
   }
 
+  void NotifyActorTaskStateChanged(const actor::ActorTask& task) {
+    const mojom::ActorTaskState state = [&]() {
+      switch (task.GetState()) {
+        case actor::ActorTask::State::kCreated:
+        case actor::ActorTask::State::kReflecting:
+          return mojom::ActorTaskState::kIdle;
+        case actor::ActorTask::State::kActing:
+          return mojom::ActorTaskState::kActing;
+        case actor::ActorTask::State::kPausedByClient:
+          return mojom::ActorTaskState::kPaused;
+        case actor::ActorTask::State::kFinished:
+          return mojom::ActorTaskState::kStopped;
+      }
+    }();
+    web_client_->NotifyActorTaskStateChanged(task.id().value(), state);
+  }
+
   glic::mojom::FocusedTabDataPtr cached_focused_tab_data_ = nullptr;
   PrefChangeRegistrar pref_change_registrar_;
   PrefChangeRegistrar local_state_pref_change_registrar_;
@@ -1354,6 +1416,7 @@
   base::CallbackListSubscription pinned_tabs_changed_subscription_;
   base::CallbackListSubscription pinned_tab_data_changed_subscription_;
   base::CallbackListSubscription focus_data_changed_subscription_;
+  base::CallbackListSubscription actor_task_state_changed_subscription_;
   mojo::Receiver<glic::mojom::WebClientHandler> receiver_;
   mojo::Remote<glic::mojom::WebClient> web_client_;
   std::unique_ptr<BrowserAttachObservation> browser_attach_observation_;
diff --git a/chrome/browser/glic/media/BUILD.gn b/chrome/browser/glic/media/BUILD.gn
index 1ed7893a..351592c19 100644
--- a/chrome/browser/glic/media/BUILD.gn
+++ b/chrome/browser/glic/media/BUILD.gn
@@ -12,6 +12,8 @@
     "glic_media_context.h",
     "glic_media_integration.cc",
     "glic_media_integration.h",
+    "glic_media_link_helper.cc",
+    "glic_media_link_helper.h",
     "glic_media_page_cache.cc",
     "glic_media_page_cache.h",
   ]
@@ -35,6 +37,7 @@
   sources = [
     "glic_media_context_unittest.cc",
     "glic_media_integration_unittest.cc",
+    "glic_media_link_helper_unittest.cc",
     "glic_media_page_cache_unittest.cc",
   ]
   deps = [
diff --git a/chrome/browser/glic/media/glic_media_link_helper.cc b/chrome/browser/glic/media/glic_media_link_helper.cc
new file mode 100644
index 0000000..bb67b99
--- /dev/null
+++ b/chrome/browser/glic/media/glic_media_link_helper.cc
@@ -0,0 +1,85 @@
+// 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 "chrome/browser/glic/media/glic_media_link_helper.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "content/public/browser/media_session.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/url_util.h"
+#include "url/origin.h"
+
+namespace glic {
+
+GlicMediaLinkHelper::GlicMediaLinkHelper(content::WebContents* web_contents)
+    : web_contents_(web_contents) {}
+
+GlicMediaLinkHelper::~GlicMediaLinkHelper() = default;
+
+bool GlicMediaLinkHelper::MaybeReplaceNavigation(const GURL& target) {
+  auto target_origin = url::Origin::Create(target);
+
+  // Insist that the target and the focused contents are the same origin.
+  if (target_origin !=
+      web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin()) {
+    return false;
+  }
+
+  if (target_origin == url::Origin::Create(GURL("https://www.youtube.com/"))) {
+    return YouTubeHelper(target);
+  }
+  // Add other origins here.
+
+  return false;
+}
+
+bool GlicMediaLinkHelper::YouTubeHelper(const GURL& target) {
+  // If `target` points to the same video as `web_contents` but contains a `t=`
+  // parameter, assume that the goal is to seek to that point in the current
+  // video.  This could also do a same-tab navigation instead of a MediaSession
+  // seek, but it's not very smooth.
+  auto& last_committed_url = web_contents()->GetLastCommittedURL();
+
+  // Make sure there is a v=, and that it is the same non-empty value.
+  std::string committed_v;
+  if (!net::GetValueForKeyInQuery(last_committed_url, "v", &committed_v)) {
+    return false;
+  }
+  std::string target_v;
+  if (!net::GetValueForKeyInQuery(target, "v", &target_v)) {
+    return false;
+  }
+  if (committed_v != target_v || committed_v.length() == 0) {
+    return false;
+  }
+
+  // Make sure that the target specifies a t=.
+  std::string t_string;
+  if (!net::GetValueForKeyInQuery(target, "t", &t_string)) {
+    return false;
+  }
+
+  if (!t_string.length()) {
+    return false;
+  }
+
+  unsigned int t = 0;
+  if (!base::StringToUint(t_string, &t)) {
+    return false;
+  }
+
+  if (auto* media_session = GetMediaSessionIfExists()) {
+    media_session->SeekTo(base::Seconds(t));
+    return true;
+  }
+
+  return false;
+}
+
+content::MediaSession* GlicMediaLinkHelper::GetMediaSessionIfExists() {
+  return content::MediaSession::GetIfExists(web_contents());
+}
+
+}  // namespace glic
diff --git a/chrome/browser/glic/media/glic_media_link_helper.h b/chrome/browser/glic/media/glic_media_link_helper.h
new file mode 100644
index 0000000..d12f63d
--- /dev/null
+++ b/chrome/browser/glic/media/glic_media_link_helper.h
@@ -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.
+
+#ifndef CHROME_BROWSER_GLIC_MEDIA_GLIC_MEDIA_LINK_HELPER_H_
+#define CHROME_BROWSER_GLIC_MEDIA_GLIC_MEDIA_LINK_HELPER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "url/gurl.h"
+
+namespace content {
+class MediaSession;
+class WebContents;
+}  // namespace content
+
+namespace glic {
+
+class GlicMediaLinkHelper {
+ public:
+  explicit GlicMediaLinkHelper(content::WebContents* web_contents);
+  virtual ~GlicMediaLinkHelper();
+
+  // Called when the user clicks a link to `target` while `web_contents` is the
+  // focused tab.  Returns true if the navigation should be skipped, false if it
+  // should be allowed to proceed.  When this returns true, an origin-specific
+  // helper can cause side-effects to take the place of the navigation.
+  bool MaybeReplaceNavigation(const GURL& target);
+
+  content::WebContents* web_contents() { return web_contents_; }
+
+  // Use this instead of MediaSession::GetIfExists() to make tests easier.
+  virtual content::MediaSession* GetMediaSessionIfExists();
+
+ private:
+  bool YouTubeHelper(const GURL& target);
+
+  raw_ptr<content::WebContents> web_contents_ = nullptr;
+};
+
+}  // namespace glic
+
+#endif  // CHROME_BROWSER_GLIC_MEDIA_GLIC_MEDIA_LINK_HELPER_H_
diff --git a/chrome/browser/glic/media/glic_media_link_helper_unittest.cc b/chrome/browser/glic/media/glic_media_link_helper_unittest.cc
new file mode 100644
index 0000000..8462f6dd
--- /dev/null
+++ b/chrome/browser/glic/media/glic_media_link_helper_unittest.cc
@@ -0,0 +1,242 @@
+// 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 "chrome/browser/glic/media/glic_media_link_helper.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/media_session.h"
+#include "content/public/test/mock_media_session.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace glic {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Eq;
+
+// Subclass for `GlicMediaLinkHelper` that lets us provide the `MediaSession`
+// object directly, since trying to get MediaSession::FromWebContents() to
+// return a mock is basically impossible without some fairly big changes.
+class GlicMediaLinkHelperForTest : public GlicMediaLinkHelper {
+ public:
+  GlicMediaLinkHelperForTest(content::WebContents* web_contents,
+                             content::MediaSession* media_session)
+      : GlicMediaLinkHelper(web_contents), media_session_(media_session) {}
+
+  content::MediaSession* GetMediaSessionIfExists() override {
+    return media_session_;
+  }
+
+  void clear_media_session() { media_session_ = nullptr; }
+
+ private:
+  raw_ptr<content::MediaSession> media_session_ = nullptr;
+};
+
+class GlicMediaLinkHelperTest : public ChromeRenderViewHostTestHarness {
+ public:
+  GlicMediaLinkHelperTest() = default;
+  ~GlicMediaLinkHelperTest() override = default;
+
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    media_link_helper_ = std::make_unique<GlicMediaLinkHelperForTest>(
+        web_contents(), &mock_media_session_);
+  }
+
+  void TearDown() override {
+    media_link_helper_.reset();
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
+  content::MockMediaSession& mock_media_session() {
+    return mock_media_session_;
+  }
+
+  GlicMediaLinkHelperForTest* media_link_helper() {
+    return media_link_helper_.get();
+  }
+
+ protected:
+  content::MockMediaSession mock_media_session_;
+  std::unique_ptr<GlicMediaLinkHelperForTest> media_link_helper_;
+};
+
+TEST_F(GlicMediaLinkHelperTest, DifferentOriginsReturnsFalse) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+
+  // Case 1: Committed is example.com, target is youtube.com
+  web_contents_tester->NavigateAndCommit(GURL("https://www.example.com/page"));
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123")));
+
+  // Case 2: Different subdomains of YouTube are considered different origins
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://m.youtube.com/watch?v=video123"));
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=30")));
+
+  // Case 3: Different schemes are different origins
+  web_contents_tester->NavigateAndCommit(
+      GURL("http://www.youtube.com/watch?v=video123"));
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=30")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, SameOriginNoHelperReturnsFalse) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(GURL("https://www.example.com/page"));
+
+  // example.com is not in g_origin_helpers
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.example.com/another_page")));
+}
+
+// --- YouTubeHelper Specific Tests (via MaybeReplaceNavigation) ---
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_NoVideoIdInCommittedUrl) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  // Committed URL without 'v=' parameter
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/feed/subscriptions"));
+
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=30")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_NoVideoIdInTargetUrl) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Target URL without 'v=' parameter
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/feed/subscriptions?t=30")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_DifferentVideoIds) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=different&t=30")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_EmptyVideoId) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+
+  // Committed URL with empty 'v='
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v="));
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=30")));
+
+  // Target URL with empty 'v='
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=&t=30")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_NoTimeParam) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Target URL without 't=' parameter
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&q=test")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_EmptyTimeParam) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Target URL with empty 't=' parameter
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_NonIntegerTimeParam) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Target URL with non-integer 't=' parameter
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=abc")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_NoMediaSession) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // No MediaSession attached, so MediaSession::GetIfExists will return nullptr.
+  media_link_helper()->clear_media_session();
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=60")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_WithMediaSession) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Attach a mock media session and expect SeekTo to be called.
+  EXPECT_CALL(mock_media_session(), SeekTo(Eq(base::Seconds(30)))).Times(1);
+
+  EXPECT_TRUE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=30")));
+}
+
+TEST_F(GlicMediaLinkHelperTest, YouTubeHelper_WithMediaSession_ZeroTime) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  EXPECT_CALL(mock_media_session(), SeekTo(Eq(base::Seconds(0)))).Times(1);
+
+  EXPECT_TRUE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=0")));
+}
+
+TEST_F(GlicMediaLinkHelperTest,
+       YouTubeHelper_WithMediaSession_NegativeTimeParam) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Expect SeekTo to NOT be called because base::StringToUint fails for
+  // negative numbers.
+  EXPECT_CALL(mock_media_session(), SeekTo(_)).Times(0);
+
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=-10")));
+}
+
+TEST_F(GlicMediaLinkHelperTest,
+       YouTubeHelper_WithMediaSession_FractionalTimeParam) {
+  auto* web_contents_tester = content::WebContentsTester::For(web_contents());
+  web_contents_tester->NavigateAndCommit(
+      GURL("https://www.youtube.com/watch?v=video123"));
+
+  // Expect SeekTo to NOT be called because base::StringToUint fails for
+  // non-integers, which also don't work for `t=` parameters.
+  EXPECT_CALL(mock_media_session(), SeekTo(_)).Times(0);
+
+  EXPECT_FALSE(media_link_helper()->MaybeReplaceNavigation(
+      GURL("https://www.youtube.com/watch?v=video123&t=10.5")));
+}
+
+}  // namespace
+}  // namespace glic
diff --git a/chrome/browser/hub/internal/BUILD.gn b/chrome/browser/hub/internal/BUILD.gn
index d92ce09..556dcb1 100644
--- a/chrome/browser/hub/internal/BUILD.gn
+++ b/chrome/browser/hub/internal/BUILD.gn
@@ -18,6 +18,7 @@
   ]
   sources = [
     "android/java/src/org/chromium/chrome/browser/hub/ApplyButtonData.java",
+    "android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java",
     "android/java/src/org/chromium/chrome/browser/hub/FadeHubLayoutAnimationFactory.java",
     "android/java/src/org/chromium/chrome/browser/hub/FadeHubLayoutAnimationFactoryImpl.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubActionButtonCoordinator.java",
@@ -25,6 +26,13 @@
     "android/java/src/org/chromium/chrome/browser/hub/HubActionButtonMediator.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubActionButtonProperties.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubActionButtonViewBinder.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegateFactory.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediator.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarProperties.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarView.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewBinder.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubColorBlendAnimatorSetHelper.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubColorMixerImpl.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubColorSchemeUpdate.java",
@@ -104,6 +112,7 @@
     "android/res/drawable/hub_pane_switcher_item_selector.xml",
     "android/res/drawable/hub_search_box_background.xml",
     "android/res/drawable/new_tab_button_background.xml",
+    "android/res/layout/hub_bottom_toolbar_layout.xml",
     "android/res/layout/hub_layout.xml",
     "android/res/layout/hub_overlay_container.xml",
     "android/res/layout/hub_pane_host_layout.xml",
@@ -161,6 +170,9 @@
     "android/java/src/org/chromium/chrome/browser/hub/FadeHubLayoutAnimationFactoryImplUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubActionButtonMediatorUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubActionButtonViewUnitTest.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediatorUnitTest.java",
+    "android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubColorMixerImplUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java",
     "android/java/src/org/chromium/chrome/browser/hub/HubLayoutAnimationRunnerImplUnitTest.java",
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java
new file mode 100644
index 0000000..32df464
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/EmptyHubBottomToolbarDelegate.java
@@ -0,0 +1,63 @@
+// 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.hub;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
+/**
+ * Empty implementation of HubBottomToolbarDelegate for testing purposes.
+ *
+ * <p>This implementation provides a basic empty bottom toolbar view and no bottom toolbar
+ * functionality and can be used in tests to verify that the delegate integration works correctly
+ * without requiring a full implementation.
+ */
+@NullMarked
+public class EmptyHubBottomToolbarDelegate implements HubBottomToolbarDelegate {
+    /** Visibility supplier that always emits false. */
+    private final ObservableSupplierImpl<Boolean> mVisibilitySupplier =
+            new ObservableSupplierImpl<>(false);
+
+    @Override
+    public @Nullable HubBottomToolbarView initializeBottomToolbarView(
+            Context context,
+            ViewGroup container,
+            PaneManager paneManager,
+            HubColorMixer hubColorMixer) {
+        // Inflate the basic empty bottom toolbar layout
+        HubBottomToolbarView hubBottomToolbarView =
+                (HubBottomToolbarView)
+                        LayoutInflater.from(context)
+                                .inflate(R.layout.hub_bottom_toolbar_layout, container, false);
+
+        // Add the basic layout to container
+        container.addView(hubBottomToolbarView);
+
+        return hubBottomToolbarView;
+    }
+
+    @Override
+    public boolean isBottomToolbarEnabled() {
+        // Bottom toolbar is not enabled in the empty implementation
+        return false;
+    }
+
+    @Override
+    public ObservableSupplier<Boolean> getBottomToolbarVisibilitySupplier() {
+        // Return a supplier that always indicates the toolbar is not visible
+        return mVisibilitySupplier;
+    }
+
+    @Override
+    public void destroy() {
+        // No resources to clean up in the empty implementation
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubActionButtonHelper.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubActionButtonHelper.java
index c9f3eee..cf5c869 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubActionButtonHelper.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubActionButtonHelper.java
@@ -11,10 +11,9 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.support.annotation.Px;
-import android.view.Gravity;
 import android.view.TouchDelegate;
+import android.view.ViewGroup;
 import android.widget.Button;
-import android.widget.FrameLayout;
 
 import androidx.annotation.ColorInt;
 import androidx.core.widget.TextViewCompat;
@@ -31,7 +30,6 @@
         ApplyButtonData.apply(buttonData, button);
         button.setText(null);
         button.setCompoundDrawablePadding(0);
-
         if (HubUtils.isGtsUpdateEnabled()) {
             Resources resources = button.getResources();
             @Px
@@ -43,19 +41,10 @@
             int buttonSize =
                     resources.getDimensionPixelSize(R.dimen.hub_toolbar_action_button_size);
 
-            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) button.getLayoutParams();
+            ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) button.getLayoutParams();
             params.width = buttonSize;
             params.height = buttonSize;
 
-            // Only set start margin if the button is positioned at the start
-            if ((params.gravity & Gravity.START) == Gravity.START) {
-                @Px
-                int startMarginPx =
-                        resources.getDimensionPixelSize(
-                                R.dimen.hub_toolbar_action_button_start_margin);
-                params.setMarginStart(startMarginPx);
-            }
-
             button.setLayoutParams(params);
         }
     }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java
new file mode 100644
index 0000000..1226d96
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinator.java
@@ -0,0 +1,68 @@
+// 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.hub;
+
+import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
+
+import android.content.Context;
+import android.view.ViewGroup;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+
+/**
+ * Coordinator for the Hub bottom toolbar. This class is responsible for setting up the component
+ * that handles the bottom toolbar of the Hub.
+ */
+@NullMarked
+public class HubBottomToolbarCoordinator {
+    /** Mediator that handles business logic for the bottom toolbar. */
+    private final HubBottomToolbarMediator mMediator;
+
+    /** The delegate that provides bottom toolbar functionality. */
+    private final HubBottomToolbarDelegate mDelegate;
+
+    /**
+     * Creates a new HubBottomToolbarCoordinator.
+     *
+     * @param context The current context.
+     * @param container The container where the bottom toolbar should be added.
+     * @param paneManager Interact with the current and all {@link Pane}s.
+     * @param hubColorMixer Mixes the Hub Overview Color.
+     * @param delegate The delegate that provides bottom toolbar functionality.
+     */
+    public HubBottomToolbarCoordinator(
+            Context context,
+            ViewGroup container,
+            PaneManager paneManager,
+            HubColorMixer hubColorMixer,
+            HubBottomToolbarDelegate delegate) {
+        mDelegate = delegate;
+
+        PropertyModel model =
+                new PropertyModel.Builder(HubBottomToolbarProperties.ALL_BOTTOM_KEYS)
+                        .with(COLOR_MIXER, hubColorMixer)
+                        .build();
+
+        // Initialize the bottom toolbar view through the delegate
+        HubBottomToolbarView hubBottomToolbarView =
+                mDelegate.initializeBottomToolbarView(
+                        context, container, paneManager, hubColorMixer);
+
+        if (hubBottomToolbarView != null) {
+            PropertyModelChangeProcessor.create(
+                    model, hubBottomToolbarView, HubBottomToolbarViewBinder::bind);
+        }
+
+        mMediator = new HubBottomToolbarMediator(model, mDelegate);
+    }
+
+    /** Cleans up observers and resources. */
+    public void destroy() {
+        mMediator.destroy();
+        mDelegate.destroy();
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java
new file mode 100644
index 0000000..134b128b
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarCoordinatorUnitTest.java
@@ -0,0 +1,90 @@
+// 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.hub;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.R;
+import org.chromium.ui.base.TestActivity;
+
+/** Tests for {@link HubBottomToolbarCoordinator}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class HubBottomToolbarCoordinatorUnitTest {
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Rule
+    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
+            new ActivityScenarioRule<>(TestActivity.class);
+
+    @Mock private PaneManager mPaneManager;
+    @Mock private HubColorMixer mHubColorMixer;
+
+    private Activity mActivity;
+    private FrameLayout mContainer;
+
+    @Before
+    public void setUp() {
+        mActivityScenarioRule.getScenario().onActivity(this::onActivity);
+    }
+
+    private void onActivity(Activity activity) {
+        mActivity = activity;
+        mContainer = new FrameLayout(activity);
+        activity.setContentView(mContainer);
+    }
+
+    @Test
+    @SmallTest
+    public void testDestroy() {
+        HubBottomToolbarDelegate emptyDelegate = spy(new EmptyHubBottomToolbarDelegate());
+        HubBottomToolbarCoordinator coordinator =
+                new HubBottomToolbarCoordinator(
+                        mActivity, mContainer, mPaneManager, mHubColorMixer, emptyDelegate);
+        coordinator.destroy();
+        verify(emptyDelegate).destroy();
+    }
+
+    @Test
+    @SmallTest
+    public void testInitializeBottomToolbarView() {
+        HubBottomToolbarDelegate emptyDelegate = spy(new EmptyHubBottomToolbarDelegate());
+        HubBottomToolbarCoordinator coordinator =
+                new HubBottomToolbarCoordinator(
+                        mActivity, mContainer, mPaneManager, mHubColorMixer, emptyDelegate);
+
+        // Verify initializeBottomToolbarView was called
+        verify(emptyDelegate)
+                .initializeBottomToolbarView(mActivity, mContainer, mPaneManager, mHubColorMixer);
+
+        // EmptyDelegate should have created and added a view to the container
+        assertTrue(mContainer.getChildCount() > 0);
+
+        // The view should be a HubBottomToolbarView
+        View addedView = mContainer.getChildAt(0);
+        HubBottomToolbarView bottomToolbarView = addedView.findViewById(R.id.hub_bottom_toolbar);
+        assertNotNull(bottomToolbarView);
+
+        coordinator.destroy();
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java
new file mode 100644
index 0000000..8f5e35c
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegate.java
@@ -0,0 +1,61 @@
+// 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.hub;
+
+import android.content.Context;
+import android.view.ViewGroup;
+
+import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
+/**
+ * Delegate interface for Hub bottom toolbar functionality.
+ *
+ * <p>This interface provides an abstraction layer for bottom toolbar operations, allowing
+ * downstream implementations to provide custom bottom toolbar functionality while keeping the
+ * upstream code generic and minimal.
+ *
+ * <p>Upstream provides an empty implementation that returns null/false for all operations, ensuring
+ * no bottom toolbar functionality is active by default. Downstream implementations can provide full
+ * bottom toolbar functionality by implementing this interface.
+ */
+@NullMarked
+public interface HubBottomToolbarDelegate {
+    /**
+     * Initializes and returns the bottom toolbar view.
+     *
+     * <p>This method is responsible for inflating the bottom toolbar layout and attaching it to the
+     * provided container.
+     *
+     * @param context The context for inflating layouts and accessing resources.
+     * @param container The parent container where the bottom toolbar should be added.
+     * @param paneManager The pane manager for observing pane changes and state.
+     * @param hubColorMixer Mixes the Hub Overview Color.
+     * @return The initialized HubBottomToolbarView, or null if bottom toolbar is not supported.
+     */
+    @Nullable HubBottomToolbarView initializeBottomToolbarView(
+            Context context,
+            ViewGroup container,
+            PaneManager paneManager,
+            HubColorMixer hubColorMixer);
+
+    /**
+     * Returns whether bottom toolbar functionality is enabled.
+     *
+     * @return True if bottom toolbar should be enabled, false otherwise.
+     */
+    boolean isBottomToolbarEnabled();
+
+    /**
+     * Returns an observable supplier for bottom toolbar visibility state.
+     *
+     * @return ObservableSupplier that emits Boolean values indicating toolbar visibility.
+     */
+    ObservableSupplier<Boolean> getBottomToolbarVisibilitySupplier();
+
+    /** Cleans up resources and unregisters any observers or callbacks. */
+    void destroy();
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegateFactory.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegateFactory.java
new file mode 100644
index 0000000..e8716399
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarDelegateFactory.java
@@ -0,0 +1,58 @@
+// 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.hub;
+
+import org.chromium.base.ResettersForTesting;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+
+/**
+ * Factory for creating HubBottomToolbarDelegate instances.
+ *
+ * <p>This factory provides a central point for delegate creation, allowing downstream
+ * implementations to override the default behavior while maintaining upstream compatibility.
+ *
+ * <p>By default, this factory returns null, meaning no bottom toolbar functionality is provided in
+ * upstream Chromium. Downstream implementations can override the factory method to provide their
+ * own delegate implementations.
+ */
+@NullMarked
+public class HubBottomToolbarDelegateFactory {
+    /** Test-only override for the delegate instance. */
+    private static @Nullable HubBottomToolbarDelegate sDelegateForTesting;
+
+    /**
+     * Creates a HubBottomToolbarDelegate instance.
+     *
+     * <p>This method returns null by default in upstream Chromium, ensuring no bottom toolbar
+     * functionality is active. Downstream implementations can override this method to return their
+     * own delegate implementations.
+     *
+     * @return A HubBottomToolbarDelegate instance, or null if no bottom toolbar functionality
+     *     should be provided.
+     */
+    public static @Nullable HubBottomToolbarDelegate createDelegate() {
+        if (sDelegateForTesting != null) {
+            return sDelegateForTesting;
+        }
+
+        // Upstream default: no bottom toolbar functionality
+        // Downstream implementations can override this method to return their delegate
+        return null;
+    }
+
+    /**
+     * Sets a delegate instance for testing purposes only.
+     *
+     * <p>This method allows tests to provide custom delegate implementations to verify that the
+     * integration works correctly without requiring full downstream implementations.
+     *
+     * @param delegate The delegate to use for testing.
+     */
+    public static void setDelegateForTesting(@Nullable HubBottomToolbarDelegate delegate) {
+        sDelegateForTesting = delegate;
+        ResettersForTesting.register(() -> sDelegateForTesting = null);
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediator.java
new file mode 100644
index 0000000..7e99b6f
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediator.java
@@ -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.
+
+package org.chromium.chrome.browser.hub;
+
+import static org.chromium.chrome.browser.hub.HubBottomToolbarProperties.BOTTOM_TOOLBAR_VISIBLE;
+
+import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Mediator for the Hub bottom toolbar. This class handles the business logic and state management
+ * for the bottom toolbar component.
+ */
+@NullMarked
+public class HubBottomToolbarMediator {
+    private final PropertyModel mPropertyModel;
+    private final HubBottomToolbarDelegate mDelegate;
+    private final Callback<Boolean> mOnVisibilityChange = this::onVisibilityChange;
+
+    /**
+     * Creates a new HubBottomToolbarMediator.
+     *
+     * @param propertyModel The property model to update with toolbar state.
+     * @param delegate The delegate that provides visibility information.
+     */
+    public HubBottomToolbarMediator(
+            PropertyModel propertyModel, HubBottomToolbarDelegate delegate) {
+        mPropertyModel = propertyModel;
+        mDelegate = delegate;
+
+        mDelegate.getBottomToolbarVisibilitySupplier().addObserver(mOnVisibilityChange);
+    }
+
+    /** Cleans up observers and unregisters callbacks. */
+    public void destroy() {
+        mDelegate.getBottomToolbarVisibilitySupplier().removeObserver(mOnVisibilityChange);
+    }
+
+    private void onVisibilityChange(Boolean visible) {
+        mPropertyModel.set(BOTTOM_TOOLBAR_VISIBLE, visible != null ? visible : false);
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediatorUnitTest.java
new file mode 100644
index 0000000..0c1d2c0
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarMediatorUnitTest.java
@@ -0,0 +1,86 @@
+// 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.hub;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import static org.chromium.chrome.browser.hub.HubBottomToolbarProperties.BOTTOM_TOOLBAR_VISIBLE;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/** Tests for {@link HubBottomToolbarMediator}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class HubBottomToolbarMediatorUnitTest {
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private PropertyModel mModel;
+    private ObservableSupplierImpl<Boolean> mVisibilitySupplier;
+    private HubBottomToolbarDelegate mDelegate;
+
+    @Before
+    public void setUp() {
+        mModel = new PropertyModel.Builder(HubBottomToolbarProperties.ALL_BOTTOM_KEYS).build();
+
+        mVisibilitySupplier = new ObservableSupplierImpl<>();
+        mDelegate =
+                new EmptyHubBottomToolbarDelegate() {
+                    @Override
+                    public ObservableSupplierImpl<Boolean> getBottomToolbarVisibilitySupplier() {
+                        return mVisibilitySupplier;
+                    }
+                };
+    }
+
+    @Test
+    @SmallTest
+    public void testMediatorWithDelegate() {
+        HubBottomToolbarMediator mediator = new HubBottomToolbarMediator(mModel, mDelegate);
+
+        // Verify that the mediator observes the visibility supplier
+        assertTrue(mVisibilitySupplier.hasObservers());
+
+        mediator.destroy();
+
+        // After destroy, observers should be removed
+        assertFalse(mVisibilitySupplier.hasObservers());
+    }
+
+    @Test
+    @SmallTest
+    public void testVisibilityChanges() {
+        HubBottomToolbarMediator mediator = new HubBottomToolbarMediator(mModel, mDelegate);
+
+        // Initially should be false (default from empty supplier)
+        mVisibilitySupplier.set(false);
+        assertEquals(false, mModel.get(BOTTOM_TOOLBAR_VISIBLE));
+
+        // Change to visible
+        mVisibilitySupplier.set(true);
+        assertEquals(true, mModel.get(BOTTOM_TOOLBAR_VISIBLE));
+
+        // Change back to hidden
+        mVisibilitySupplier.set(false);
+        assertEquals(false, mModel.get(BOTTOM_TOOLBAR_VISIBLE));
+
+        // Test null value handling
+        mVisibilitySupplier.set(null);
+        assertEquals(false, mModel.get(BOTTOM_TOOLBAR_VISIBLE));
+
+        mediator.destroy();
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarProperties.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarProperties.java
new file mode 100644
index 0000000..b90e74d6
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarProperties.java
@@ -0,0 +1,24 @@
+// 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.hub;
+
+import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+
+/** Responsible for holding properties of the bottom toolbar in the hub. */
+@NullMarked
+class HubBottomToolbarProperties {
+    // The visibility of the bottom toolbar.
+    public static final WritableBooleanPropertyKey BOTTOM_TOOLBAR_VISIBLE =
+            new WritableBooleanPropertyKey();
+
+    // All property keys for the bottom toolbar.
+    static final PropertyKey[] ALL_BOTTOM_KEYS = {
+        COLOR_MIXER, BOTTOM_TOOLBAR_VISIBLE,
+    };
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarView.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarView.java
new file mode 100644
index 0000000..12b703a1
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarView.java
@@ -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.
+
+package org.chromium.chrome.browser.hub;
+
+import static org.chromium.chrome.browser.hub.HubAnimationConstants.PANE_COLOR_BLEND_ANIMATION_DURATION_MS;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+import org.chromium.build.annotations.NullMarked;
+
+/** Basic view that represents the bottom toolbar in the Hub. */
+@NullMarked
+public class HubBottomToolbarView extends LinearLayout {
+    /** Default {@link LinearLayout} constructor called by inflation. */
+    public HubBottomToolbarView(Context context, AttributeSet attributeSet) {
+        super(context, attributeSet);
+    }
+
+    void setColorMixer(HubColorMixer mixer) {
+        Context context = getContext();
+
+        mixer.registerBlend(
+                new SingleHubViewColorBlend(
+                        PANE_COLOR_BLEND_ANIMATION_DURATION_MS,
+                        colorScheme -> HubColors.getBackgroundColor(context, colorScheme),
+                        this::setBackgroundColor));
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewBinder.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewBinder.java
new file mode 100644
index 0000000..d8e102b
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewBinder.java
@@ -0,0 +1,28 @@
+// 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.hub;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static org.chromium.chrome.browser.hub.HubBottomToolbarProperties.BOTTOM_TOOLBAR_VISIBLE;
+import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/** Responsible for applying properties to the bottom toolbar in the hub. */
+@NullMarked
+public class HubBottomToolbarViewBinder {
+    public static void bind(PropertyModel model, HubBottomToolbarView view, PropertyKey key) {
+        if (key == COLOR_MIXER) {
+            view.setColorMixer(model.get(COLOR_MIXER));
+        } else if (key == BOTTOM_TOOLBAR_VISIBLE) {
+            boolean isVisible = model.get(BOTTOM_TOOLBAR_VISIBLE);
+            view.setVisibility(isVisible ? VISIBLE : GONE);
+        }
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewUnitTest.java
new file mode 100644
index 0000000..7face4af
--- /dev/null
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubBottomToolbarViewUnitTest.java
@@ -0,0 +1,86 @@
+// 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.hub;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static org.junit.Assert.assertEquals;
+
+import static org.chromium.chrome.browser.hub.HubBottomToolbarProperties.BOTTOM_TOOLBAR_VISIBLE;
+import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
+
+import android.app.Activity;
+import android.view.LayoutInflater;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.R;
+import org.chromium.ui.base.TestActivity;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+
+/** Unit tests for {@link HubBottomToolbarView} and {@link HubBottomToolbarViewBinder}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class HubBottomToolbarViewUnitTest {
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Rule
+    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
+            new ActivityScenarioRule<>(TestActivity.class);
+
+    @Mock private HubColorMixer mHubColorMixer;
+
+    private HubBottomToolbarView mBottomToolbarView;
+    private PropertyModel mPropertyModel;
+
+    @Before
+    public void setUp() {
+        mActivityScenarioRule.getScenario().onActivity(this::onActivity);
+    }
+
+    private void onActivity(Activity activity) {
+        mBottomToolbarView =
+                (HubBottomToolbarView)
+                        LayoutInflater.from(activity)
+                                .inflate(R.layout.hub_bottom_toolbar_layout, null, false);
+
+        mPropertyModel =
+                new PropertyModel.Builder(HubBottomToolbarProperties.ALL_BOTTOM_KEYS)
+                        .with(COLOR_MIXER, mHubColorMixer)
+                        .with(BOTTOM_TOOLBAR_VISIBLE, false)
+                        .build();
+
+        PropertyModelChangeProcessor.create(
+                mPropertyModel, mBottomToolbarView, HubBottomToolbarViewBinder::bind);
+
+        activity.setContentView(mBottomToolbarView);
+    }
+
+    @Test
+    @SmallTest
+    public void testVisibilityToggle() {
+        // Initial state should be GONE
+        assertEquals(GONE, mBottomToolbarView.getVisibility());
+
+        // Test setting visibility to true
+        mPropertyModel.set(BOTTOM_TOOLBAR_VISIBLE, true);
+        assertEquals(VISIBLE, mBottomToolbarView.getVisibility());
+
+        // Test setting visibility to false
+        mPropertyModel.set(BOTTOM_TOOLBAR_VISIBLE, false);
+        assertEquals(GONE, mBottomToolbarView.getVisibility());
+    }
+}
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubColors.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubColors.java
index aacbc2a..f63c467 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubColors.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubColors.java
@@ -220,6 +220,29 @@
         }
     }
 
+    /**
+     * Adapts the given color to a color state list that supports enabled and disabled states.
+     *
+     * @param context The {@link Context} to use for the color state list.
+     * @param enabledColor The color to use for the enabled state.
+     * @return A {@link ColorStateList} with the given color for the enabled state and a disabled
+     *     state.
+     */
+    public static ColorStateList getButtonColorStateList(
+            Context context, @ColorInt int enabledColor) {
+        @DimenRes int disabledAlpha = R.dimen.default_disabled_alpha;
+        return generateDisabledAndNormalStatesColorStateList(context, enabledColor, disabledAlpha);
+    }
+
+    /**
+     * Adapts the given color to a color state list that supports enabled and disabled states for
+     * the hub action button.
+     *
+     * @param context The {@link Context} to use for the color state list.
+     * @param enabledColor The color to use for the enabled state.
+     * @return A {@link ColorStateList} with the given color for the enabled state and a disabled
+     *     state.
+     */
     public static ColorStateList getActionButtonColor(
             Context context, @ColorInt int enabledColor, boolean isGtsUpdateEnabled) {
         if (isGtsUpdateEnabled) {
@@ -228,10 +251,18 @@
             return generateDisabledAndNormalStatesColorStateList(enabledColor, disabledColor);
         }
 
-        @DimenRes int disabledAlpha = R.dimen.default_disabled_alpha;
-        return generateDisabledAndNormalStatesColorStateList(context, enabledColor, disabledAlpha);
+        return getButtonColorStateList(context, enabledColor);
     }
 
+    /**
+     * Adapts the given color to a color state list that supports enabled and disabled states for
+     * the hub action button background.
+     *
+     * @param context The {@link Context} to use for the color state list.
+     * @param enabledColor The color to use for the enabled state.
+     * @return A {@link ColorStateList} with the given color for the enabled state and a disabled
+     *     state.
+     */
     public static ColorStateList getActionButtonBgColor(Context context, @ColorInt int color) {
         @ColorRes int disabledColorRes = R.color.hub_action_button_disabled_background_color;
         @ColorInt int disabledColor = ContextCompat.getColor(context, disabledColorRes);
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java
index c9a8e9e6..9f765a6 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinator.java
@@ -15,6 +15,7 @@
 import android.widget.FrameLayout;
 
 import org.chromium.base.Callback;
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneshotSupplier;
@@ -41,6 +42,7 @@
     private final ViewGroup mMainHubParent;
     private final PaneManager mPaneManager;
     private final HubToolbarCoordinator mHubToolbarCoordinator;
+    private final @Nullable HubBottomToolbarCoordinator mHubBottomToolbarCoordinator;
     private final HubPaneHostCoordinator mHubPaneHostCoordinator;
     private final SingleChildViewManager mOverlayViewManager;
     private final HubLayoutController mHubLayoutController;
@@ -51,7 +53,7 @@
      * Generic callback that invokes {@link #updateHandleBackPressSupplier()}. This can be cast to
      * an arbitrary {@link Callback} and the provided value is discarded.
      */
-    private final Callback<Object> mBackPressStateChangeCallback;
+    private final Callback<@Nullable Object> mBackPressStateChangeCallback;
 
     /**
      * Warning: {@link #getFocusedPane()} may return null if no pane is focused or {@link
@@ -60,7 +62,7 @@
     private final TransitiveObservableSupplier<Pane, Boolean> mFocusedPaneHandleBackPressSupplier;
 
     private final PaneBackStackHandler mPaneBackStackHandler;
-    private final ObservableSupplier<Tab> mCurrentTabSupplier;
+    private final ObservableSupplier<@Nullable Tab> mCurrentTabSupplier;
     private @Nullable EdgeToEdgePadAdjuster mEdgeToEdgePadAdjuster;
 
     /**
@@ -85,7 +87,7 @@
             FrameLayout containerView,
             PaneManager paneManager,
             HubLayoutController hubLayoutController,
-            ObservableSupplier<Tab> currentTabSupplier,
+            ObservableSupplier<@Nullable Tab> currentTabSupplier,
             MenuButtonCoordinator menuButtonCoordinator,
             SearchActivityClient searchActivityClient,
             ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
@@ -115,6 +117,15 @@
 
         UserEducationHelper userEducationHelper =
                 new UserEducationHelper(activity, profile, new Handler());
+
+        // Get bottom toolbar delegate and visibility supplier
+        HubBottomToolbarDelegate bottomToolbarDelegate =
+                HubBottomToolbarDelegateFactory.createDelegate();
+        @Nullable ObservableSupplier<Boolean> bottomToolbarVisibilitySupplier =
+                bottomToolbarDelegate != null
+                        ? bottomToolbarDelegate.getBottomToolbarVisibilitySupplier()
+                        : null;
+
         mHubToolbarCoordinator =
                 new HubToolbarCoordinator(
                         activity,
@@ -125,7 +136,27 @@
                         searchActivityClient,
                         hubColorMixer,
                         userEducationHelper,
-                        hubLayoutController.getIsAnimatingSupplier());
+                        hubLayoutController.getIsAnimatingSupplier(),
+                        bottomToolbarVisibilitySupplier,
+                        currentTabSupplier,
+                        () -> {
+                            RecordUserAction.record("Hub.BackButtonPressed");
+                            selectCurrentTabAndHideHub();
+                        });
+
+        // Dynamically add bottom toolbar if delegate is available and enabled
+        if (bottomToolbarDelegate != null && bottomToolbarDelegate.isBottomToolbarEnabled()) {
+            ViewGroup mainContainer = mContainerView.findViewById(R.id.hub_main_container);
+            mHubBottomToolbarCoordinator =
+                    new HubBottomToolbarCoordinator(
+                            context,
+                            mainContainer,
+                            paneManager,
+                            hubColorMixer,
+                            bottomToolbarDelegate);
+        } else {
+            mHubBottomToolbarCoordinator = null;
+        }
 
         HubPaneHostView hubPaneHostView = mContainerView.findViewById(R.id.hub_pane_host);
         hubPaneHostView.setXrSpaceModeObservableSupplier(xrSpaceModeObservableSupplier);
@@ -152,7 +183,7 @@
                 .addObserver(castCallback(mBackPressStateChangeCallback));
 
         mCurrentTabSupplier = currentTabSupplier;
-        mCurrentTabSupplier.addObserver(castCallback(mBackPressStateChangeCallback));
+        setCurrentTabSupplierObserver();
 
         mHubLayoutController
                 .getPreviousLayoutTypeSupplier()
@@ -163,7 +194,13 @@
         mHubSearchBoxBackgroundCoordinator = new HubSearchBoxBackgroundCoordinator(mContainerView);
     }
 
+    @SuppressWarnings("NullAway")
+    private void setCurrentTabSupplierObserver() {
+        mCurrentTabSupplier.addObserver(castCallback(mBackPressStateChangeCallback));
+    }
+
     /** Removes the hub from the layout tree and cleans up resources. */
+    @SuppressWarnings("NullAway")
     public void destroy() {
         mContainerView.removeView(mMainHubParent);
 
@@ -179,6 +216,9 @@
         mPaneBackStackHandler.destroy();
 
         mHubToolbarCoordinator.destroy();
+        if (mHubBottomToolbarCoordinator != null) {
+            mHubBottomToolbarCoordinator.destroy();
+        }
         mHubPaneHostCoordinator.destroy();
         mOverlayViewManager.destroy();
 
@@ -200,12 +240,8 @@
             return BackPressResult.SUCCESS;
         }
 
-        Tab tab = mCurrentTabSupplier.get();
-        if (tab != null) {
-            mHubLayoutController.selectTabAndHideHubLayout(tab.getId());
-            return BackPressResult.SUCCESS;
-        }
-        return BackPressResult.FAILURE;
+        boolean success = selectCurrentTabAndHideHub();
+        return success ? BackPressResult.SUCCESS : BackPressResult.FAILURE;
     }
 
     @Nullable
@@ -216,12 +252,7 @@
             return true;
         }
 
-        Tab tab = mCurrentTabSupplier.get();
-        if (tab != null) {
-            mHubLayoutController.selectTabAndHideHubLayout(tab.getId());
-            return true;
-        }
-        return false;
+        return selectCurrentTabAndHideHub();
     }
 
     @Override
@@ -261,6 +292,15 @@
                 assumeNonNull(getFocusedPane()).getColorScheme());
     }
 
+    private boolean selectCurrentTabAndHideHub() {
+        Tab tab = mCurrentTabSupplier.get();
+        if (tab != null) {
+            mHubLayoutController.selectTabAndHideHubLayout(tab.getId());
+            return true;
+        }
+        return false;
+    }
+
     /** Returns the view group to contain the snackbar. */
     public ViewGroup getSnackbarContainer() {
         return mHubPaneHostCoordinator.getSnackbarContainer();
@@ -278,7 +318,12 @@
         mHandleBackPressSupplier.set(shouldHandleBackPress);
     }
 
+    @SuppressWarnings("NullAway")
     private <T> Callback<T> castCallback(Callback callback) {
         return (Callback<T>) callback;
     }
+
+    @Nullable HubBottomToolbarCoordinator getHubBottomToolbarCoordinatorForTesting() {
+        return mHubBottomToolbarCoordinator;
+    }
 }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java
index feaa4fd8..092be39 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubCoordinatorUnitTest.java
@@ -7,6 +7,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -342,4 +344,86 @@
         mHubCoordinator.selectTabAndHideHub(tabId);
         verify(mHubLayoutController).selectTabAndHideHubLayout(tabId);
     }
+
+    @Test
+    public void testBottomToolbarDelegate_Null() {
+        // By default, no bottom toolbar delegate is set.
+        assertNull(mHubCoordinator.getHubBottomToolbarCoordinatorForTesting());
+    }
+
+    @Test
+    public void testBottomToolbarDelegate_EmptyDelegate() {
+        // Set EmptyHubBottomToolbarDelegate for testing
+        EmptyHubBottomToolbarDelegate emptyDelegate = new EmptyHubBottomToolbarDelegate();
+        HubBottomToolbarDelegateFactory.setDelegateForTesting(emptyDelegate);
+
+        mActivityScenarioRule
+                .getScenario()
+                .onActivity(
+                        activity -> {
+                            mRootView = new FrameLayout(activity);
+                            activity.setContentView(mRootView);
+
+                            // Create coordinator with empty delegate
+                            HubCoordinator coordinator =
+                                    new HubCoordinator(
+                                            activity,
+                                            mProfileProviderSupplier,
+                                            mRootView,
+                                            mPaneManager,
+                                            mHubLayoutController,
+                                            mTabSupplier,
+                                            mMenuButtonCoordinator,
+                                            mSearchActivityClient,
+                                            mEdgeToEdgeSupplier,
+                                            mHubColorMixer,
+                                            null);
+
+                            // EmptyDelegate.isBottomToolbarEnabled() returns false,
+                            // so no bottom toolbar coordinator should be created
+                            assertNull(coordinator.getHubBottomToolbarCoordinatorForTesting());
+
+                            coordinator.destroy();
+                        });
+    }
+
+    @Test
+    public void testBottomToolbarDelegate_EnabledDelegate() {
+        // Create a custom delegate that reports as enabled
+        HubBottomToolbarDelegate enabledDelegate =
+                new EmptyHubBottomToolbarDelegate() {
+                    @Override
+                    public boolean isBottomToolbarEnabled() {
+                        return true;
+                    }
+                };
+        HubBottomToolbarDelegateFactory.setDelegateForTesting(enabledDelegate);
+
+        mActivityScenarioRule
+                .getScenario()
+                .onActivity(
+                        activity -> {
+                            mRootView = new FrameLayout(activity);
+                            activity.setContentView(mRootView);
+
+                            // Create coordinator with enabled delegate
+                            HubCoordinator coordinator =
+                                    new HubCoordinator(
+                                            activity,
+                                            mProfileProviderSupplier,
+                                            mRootView,
+                                            mPaneManager,
+                                            mHubLayoutController,
+                                            mTabSupplier,
+                                            mMenuButtonCoordinator,
+                                            mSearchActivityClient,
+                                            mEdgeToEdgeSupplier,
+                                            mHubColorMixer,
+                                            null);
+
+                            assertNotNull(coordinator.getHubBottomToolbarCoordinatorForTesting());
+
+                            coordinator.destroy();
+                        });
+    }
 }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java
index 62bfa504..5c5b035 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerFactory.java
@@ -6,11 +6,10 @@
 
 import android.app.Activity;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.profiles.ProfileProvider;
 import org.chromium.chrome.browser.tab.Tab;
@@ -41,6 +40,7 @@
      * @param xrSpaceModeObservableSupplier Supplies current XR space mode status. True for XR full
      *     space mode, false otherwise.
      */
+    @SuppressWarnings("NullAway") // https://crbug.com/433562519
     public static HubManager createHubManager(
             Activity activity,
             OneshotSupplier<ProfileProvider> profileProviderSupplier,
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java
index 263dcc0..01974ac 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubManagerImpl.java
@@ -51,7 +51,7 @@
     private final BackPressManager mBackPressManager;
     private final MenuOrKeyboardActionController mMenuOrKeyboardActionController;
     private final SnackbarManager mSnackbarManager;
-    private final ObservableSupplier<Tab> mTabSupplier;
+    private final ObservableSupplier<@Nullable Tab> mTabSupplier;
     private final MenuButtonCoordinator mMenuButtonCoordinator;
     private final HubShowPaneHelper mHubShowPaneHelper;
     private final ObservableSupplier<EdgeToEdgeController> mEdgeToEdgeSupplier;
@@ -74,7 +74,7 @@
             BackPressManager backPressManager,
             MenuOrKeyboardActionController menuOrKeyboardActionController,
             SnackbarManager snackbarManager,
-            ObservableSupplier<Tab> tabSupplier,
+            ObservableSupplier<@Nullable Tab> tabSupplier,
             MenuButtonCoordinator menuButtonCoordinator,
             HubShowPaneHelper hubShowPaneHelper,
             ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinator.java
index c88db7c5..3b4e5e95 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinator.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinator.java
@@ -15,6 +15,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.menu_button.MenuButton;
 import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator;
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient;
@@ -31,12 +32,15 @@
 @NullMarked
 public class HubToolbarCoordinator {
     private final Callback<Boolean> mIsAnimatingObserver = this::tryToTriggerAddToGroupIph;
+    private final Callback<Boolean> mBottomToolbarVisibilityObserver =
+            this::onBottomToolbarVisibilityChange;
     private final HubToolbarMediator mMediator;
     private final HubToolbarView mHubToolbarView;
     private final MenuButtonCoordinator mMenuButtonCoordinator;
     private final MenuButton mMenuButton;
     private final UserEducationHelper mUserEducationHelper;
     private final ObservableSupplier<Boolean> mIsAnimatingSupplier;
+    private final @Nullable ObservableSupplier<Boolean> mBottomToolbarVisibilitySupplier;
     private final HubActionButtonCoordinator mActionButtonCoordinator;
 
     /**
@@ -50,6 +54,9 @@
      * @param hubColorMixer Mixes the Hub Overview Color.
      * @param userEducationHelper Used to show IPHs.
      * @param isHubAnimatingSupplier Supplies whether a hub layout animation is running.
+     * @param bottomToolbarVisibilitySupplier Supplies bottom toolbar visibility state, can be null.
+     * @param currentTabSupplier The supplier of the current {@link Tab}.
+     * @param exitHubRunnable Used to exit the hub.
      */
     public HubToolbarCoordinator(
             Activity activity,
@@ -60,10 +67,14 @@
             SearchActivityClient searchActivityClient,
             HubColorMixer hubColorMixer,
             UserEducationHelper userEducationHelper,
-            ObservableSupplier<Boolean> isHubAnimatingSupplier) {
+            ObservableSupplier<Boolean> isHubAnimatingSupplier,
+            @Nullable ObservableSupplier<Boolean> bottomToolbarVisibilitySupplier,
+            ObservableSupplier<@Nullable Tab> currentTabSupplier,
+            Runnable exitHubRunnable) {
         mUserEducationHelper = userEducationHelper;
         mMenuButtonCoordinator = menuButtonCoordinator;
         mIsAnimatingSupplier = isHubAnimatingSupplier;
+        mBottomToolbarVisibilitySupplier = bottomToolbarVisibilitySupplier;
 
         Button hubActionButton = hubToolbarView.findViewById(R.id.toolbar_action_button);
         mActionButtonCoordinator =
@@ -76,9 +87,21 @@
                         .build();
         PropertyModelChangeProcessor.create(model, hubToolbarView, HubToolbarViewBinder::bind);
         mMediator =
-                new HubToolbarMediator(activity, model, paneManager, tracker, searchActivityClient);
+                new HubToolbarMediator(
+                        activity,
+                        model,
+                        paneManager,
+                        tracker,
+                        searchActivityClient,
+                        currentTabSupplier,
+                        exitHubRunnable);
         mHubToolbarView = hubToolbarView;
 
+        // Set up bottom toolbar visibility observer
+        if (mBottomToolbarVisibilitySupplier != null) {
+            mBottomToolbarVisibilitySupplier.addObserver(mBottomToolbarVisibilityObserver);
+        }
+
         mMenuButton = hubToolbarView.findViewById(R.id.menu_button_wrapper);
         ImageButton imageButton = mMenuButton.getImageButton();
         imageButton.setContentDescription(
@@ -110,6 +133,10 @@
         mIsAnimatingSupplier.removeObserver(mIsAnimatingObserver);
     }
 
+    private void onBottomToolbarVisibilityChange(boolean isVisible) {
+        mActionButtonCoordinator.onActionButtonVisibilityChange(!isVisible);
+    }
+
     /** Returns the button view for a given pane if present. */
     public @Nullable View getPaneButton(@PaneId int paneId) {
         return mMediator.getButton(paneId);
@@ -119,6 +146,9 @@
     public void destroy() {
         mMediator.destroy();
         mIsAnimatingSupplier.removeObserver(mIsAnimatingObserver);
+        if (mBottomToolbarVisibilitySupplier != null) {
+            mBottomToolbarVisibilitySupplier.removeObserver(mBottomToolbarVisibilityObserver);
+        }
         mActionButtonCoordinator.destroy();
     }
 
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinatorUnitTest.java
index 82a233d1..4ca45fbd 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinatorUnitTest.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarCoordinatorUnitTest.java
@@ -34,6 +34,7 @@
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.toolbar.menu_button.MenuButton;
 import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator;
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient;
@@ -73,9 +74,11 @@
 
     private final ObservableSupplierImpl<Pane> mFocusedPaneSupplier =
             new ObservableSupplierImpl<>();
+    private final ObservableSupplierImpl<Tab> mCurrentTabSupplier = new ObservableSupplierImpl<>();
     private HubToolbarCoordinator mCoordinator;
     private HubToolbarView mHubToolbarView;
     private MenuButton mMenuButton;
+    private ObservableSupplierImpl<Boolean> mBottomToolbarVisibilitySupplier;
 
     @Mock private PaneManager mPaneManager;
     @Mock private PaneOrderController mPaneOrderController;
@@ -84,6 +87,7 @@
     @Mock private SearchActivityClient mSearchActivityClient;
     @Mock private HubColorMixer mHubColorMixer;
     @Mock private UserEducationHelper mUserEducationHelper;
+    @Mock private Runnable mExitHubRunnable;
 
     @Before
     public void setUp() {
@@ -92,6 +96,7 @@
         when(mPaneManager.getFocusedPaneSupplier()).thenReturn(mFocusedPaneSupplier);
         when(mPaneManager.getPaneOrderController()).thenReturn(mPaneOrderController);
         when(mPaneOrderController.getPaneOrder()).thenReturn(ImmutableSet.of());
+        mBottomToolbarVisibilitySupplier = spy(new ObservableSupplierImpl<>());
         mActivityScenarioRule.getScenario().onActivity(this::onActivity);
     }
 
@@ -113,7 +118,10 @@
                         mSearchActivityClient,
                         mHubColorMixer,
                         mUserEducationHelper,
-                        mIsAnimatingSupplier);
+                        mIsAnimatingSupplier,
+                        mBottomToolbarVisibilitySupplier,
+                        mCurrentTabSupplier,
+                        mExitHubRunnable);
     }
 
     @Test
@@ -126,4 +134,16 @@
         verify(mUserEducationHelper).requestShowIph(any());
         verify(mIsAnimatingSupplier).removeObserver(any());
     }
+
+    @Test
+    public void testBottomToolbarVisibilitySupplier() {
+        // Verify that observer was added to the bottom toolbar visibility supplier
+        verify(mBottomToolbarVisibilitySupplier).addObserver(any());
+
+        // Destroy coordinator
+        mCoordinator.destroy();
+
+        // Verify that observer was removed from the bottom toolbar visibility supplier
+        verify(mBottomToolbarVisibilitySupplier).removeObserver(any());
+    }
 }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java
index c7baa5e2..b50d395b 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java
@@ -6,6 +6,9 @@
 
 import static org.chromium.build.NullUtil.assumeNonNull;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_ENABLED;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_LISTENER;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_VISIBLE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.HUB_SEARCH_ENABLED_STATE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.MENU_BUTTON_VISIBLE;
@@ -30,6 +33,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.hub.HubToolbarProperties.PaneButtonLookup;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient;
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityExtras.ResolutionType;
 import org.chromium.components.embedder_support.util.UrlConstants;
@@ -72,6 +76,10 @@
             new ComponentCallbacks() {
                 @Override
                 public void onConfigurationChanged(Configuration configuration) {
+                    int screenWidthDp = configuration.screenWidthDp;
+                    boolean isTablet = HubUtils.isScreenWidthTablet(screenWidthDp);
+                    mPropertyModel.set(BACK_BUTTON_VISIBLE, isTablet);
+
                     Pane pane = mPaneManager.getFocusedPaneSupplier().get();
                     if (pane == null) return;
 
@@ -82,14 +90,11 @@
                         mPropertyModel.set(APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION, true);
                         mPropertyModel.set(SEARCH_BOX_VISIBLE, false);
                         mPropertyModel.set(SEARCH_LOUPE_VISIBLE, false);
-                        return;
+                    } else {
+                        mPropertyModel.set(APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION, false);
+                        mPropertyModel.set(SEARCH_BOX_VISIBLE, !isTablet);
+                        mPropertyModel.set(SEARCH_LOUPE_VISIBLE, isTablet);
                     }
-
-                    int screenWidthDp = configuration.screenWidthDp;
-                    boolean showLoupe = HubUtils.isScreenWidthTablet(screenWidthDp);
-                    mPropertyModel.set(APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION, false);
-                    mPropertyModel.set(SEARCH_BOX_VISIBLE, !showLoupe);
-                    mPropertyModel.set(SEARCH_LOUPE_VISIBLE, showLoupe);
                 }
 
                 @Override
@@ -102,6 +107,7 @@
     private final PaneManager mPaneManager;
     private final Tracker mTracker;
     private final SearchActivityClient mSearchActivityClient;
+    private final ObservableSupplier<@Nullable Tab> mCurrentTabSupplier;
     // The order of entries in this map are the order the buttons should appear to the user. A null
     // value should not be shown to the user.
     private final ArrayList<Pair<Integer, @Nullable DisplayButtonData>>
@@ -113,6 +119,7 @@
     private final Callback<Pane> mOnFocusedPaneChange = this::onFocusedPaneChange;
     private final Callback<Boolean> mOnHubSearchEnabledStateChange =
             this::onHubSearchEnabledStateChange;
+    private final Callback<@Nullable Tab> mOnCurrentTabChange = this::onCurrentTabChange;
 
     private @Nullable PaneButtonLookup mPaneButtonLookup;
 
@@ -122,12 +129,15 @@
             PropertyModel propertyModel,
             PaneManager paneManager,
             Tracker tracker,
-            SearchActivityClient searchActivityClient) {
+            SearchActivityClient searchActivityClient,
+            ObservableSupplier<@Nullable Tab> currentTabSupplier,
+            Runnable exitHubRunnable) {
         mContext = context;
         mPropertyModel = propertyModel;
         mPaneManager = paneManager;
         mTracker = tracker;
         mSearchActivityClient = searchActivityClient;
+        mCurrentTabSupplier = currentTabSupplier;
 
         for (@PaneId int paneId : paneManager.getPaneOrderController().getPaneOrder()) {
             Pane pane = paneManager.getPaneForId(paneId);
@@ -156,6 +166,10 @@
         mPropertyModel.set(PANE_BUTTON_LOOKUP_CALLBACK, this::consumeButtonLookup);
 
         mPropertyModel.set(SEARCH_LISTENER, this::onSearchClicked);
+        mPropertyModel.set(BACK_BUTTON_LISTENER, exitHubRunnable);
+        mPropertyModel.set(BACK_BUTTON_ENABLED, mCurrentTabSupplier.hasValue());
+        mCurrentTabSupplier.addObserver(mOnCurrentTabChange);
+
         // Fire an event for the original setup.
         mComponentCallbacks.onConfigurationChanged(mContext.getResources().getConfiguration());
         mContext.registerComponentCallbacks(mComponentCallbacks);
@@ -167,6 +181,7 @@
         mRemoveReferenceButtonObservers.clear();
         mPaneManager.getFocusedPaneSupplier().removeObserver(mOnFocusedPaneChange);
         mContext.unregisterComponentCallbacks(mComponentCallbacks);
+        mCurrentTabSupplier.removeObserver(mOnCurrentTabChange);
 
         for (@PaneId int paneId : mPaneManager.getPaneOrderController().getPaneOrder()) {
             @Nullable Pane pane = mPaneManager.getPaneForId(paneId);
@@ -310,6 +325,10 @@
                 mPropertyModel.get(SEARCH_BOX_VISIBLE), mPropertyModel.get(IS_INCOGNITO));
     }
 
+    private void onCurrentTabChange(@Nullable Tab tab) {
+        mPropertyModel.set(BACK_BUTTON_ENABLED, tab != null);
+    }
+
     private void recordHubSearchEntrypointHistogram(boolean isSearchBox, boolean isIncognito) {
         // Based on the ComponentCallback#onConfigurationChanged logic for hub search, it is implied
         // that the search box and search loupe visibilities have opposite behaviors at any time.
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediatorUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediatorUnitTest.java
index e55b61a..a3c862c 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediatorUnitTest.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediatorUnitTest.java
@@ -14,6 +14,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -22,6 +23,9 @@
 
 import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_ENABLED;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_LISTENER;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_VISIBLE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.HUB_SEARCH_ENABLED_STATE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.MENU_BUTTON_VISIBLE;
@@ -57,6 +61,7 @@
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.chrome.browser.hub.HubToolbarMediator.HubSearchEntrypoint;
 import org.chromium.chrome.browser.hub.HubToolbarProperties.PaneButtonLookup;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient;
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityClient.IntentBuilder;
 import org.chromium.components.feature_engagement.Tracker;
@@ -93,6 +98,7 @@
     @Mock private SearchActivityClient mSearchActivityClient;
     @Mock private IntentBuilder mIntentBuilder;
     @Mock private Intent mIntent;
+    @Mock private Runnable mExitHubRunnable;
     @Mock private HubColorMixer mColorMixer;
 
     private ObservableSupplierImpl<FullButtonData> mActionButtonSupplier;
@@ -103,6 +109,7 @@
     private ObservableSupplierImpl<Boolean> mGroupsHubSearchEnabledStateSupplier;
     private ObservableSupplierImpl<DisplayButtonData>
             mIncognitoTabSwitcherReferenceButtonDataSupplier2;
+    private ObservableSupplierImpl<Tab> mCurrentTabSupplier;
     private PropertyModel mModel;
 
     @Before
@@ -114,6 +121,7 @@
         mRegularHubSearchEnabledStateSupplier = new ObservableSupplierImpl<>();
         mIncognitoHubSearchEnabledStateSupplier = new ObservableSupplierImpl<>();
         mGroupsHubSearchEnabledStateSupplier = new ObservableSupplierImpl<>();
+        mCurrentTabSupplier = new ObservableSupplierImpl<>();
         mFocusedPaneSupplier = new ObservableSupplierImpl<>();
         mModel =
                 new PropertyModel.Builder(HubToolbarProperties.ALL_KEYS)
@@ -168,7 +176,13 @@
 
         HubToolbarMediator mediator =
                 new HubToolbarMediator(
-                        mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+                        mActivity,
+                        mModel,
+                        mPaneManager,
+                        mTracker,
+                        mSearchActivityClient,
+                        mCurrentTabSupplier,
+                        mExitHubRunnable);
         assertTrue(mFocusedPaneSupplier.hasObservers());
 
         mediator.destroy();
@@ -188,7 +202,13 @@
         mFocusedPaneSupplier.set(mTabSwitcherPane);
         HubToolbarMediator mediator =
                 new HubToolbarMediator(
-                        mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+                        mActivity,
+                        mModel,
+                        mPaneManager,
+                        mTracker,
+                        mSearchActivityClient,
+                        mCurrentTabSupplier,
+                        mExitHubRunnable);
         assertTrue(mRegularHubSearchEnabledStateSupplier.hasObservers());
 
         mRegularHubSearchEnabledStateSupplier.set(false);
@@ -206,7 +226,14 @@
         when(mPaneOrderController.getPaneOrder())
                 .thenReturn(ImmutableSet.of(PaneId.TAB_SWITCHER, PaneId.INCOGNITO_TAB_SWITCHER));
         mFocusedPaneSupplier.set(mTabSwitcherPane);
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
 
         // Mimic incognito reauth pending
         mFocusedPaneSupplier.set(mIncognitoTabSwitcherPane);
@@ -226,7 +253,14 @@
     @Test
     @SmallTest
     public void testPaneSwitcherButtonData() {
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         List<FullButtonData> paneSwitcherButtonData = mModel.get(PANE_SWITCHER_BUTTON_DATA);
         assertEquals(2, paneSwitcherButtonData.size());
 
@@ -242,7 +276,14 @@
     public void testNullPane() {
         when(mPaneManager.getPaneForId(PaneId.INCOGNITO_TAB_SWITCHER)).thenReturn(null);
 
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         List<FullButtonData> paneSwitcherButtonData = mModel.get(PANE_SWITCHER_BUTTON_DATA);
         assertEquals(1, paneSwitcherButtonData.size());
 
@@ -255,7 +296,14 @@
     public void testPaneSwitcherButtonDataEventCount() {
         verify(mPropertyObserver, never()).onPropertyChanged(any(), eq(PANE_SWITCHER_BUTTON_DATA));
 
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         verify(mPropertyObserver, times(1)).onPropertyChanged(any(), eq(PANE_SWITCHER_BUTTON_DATA));
 
         mTabSwitcherReferenceButtonDataSupplier1.set(mDisplayButtonData);
@@ -271,7 +319,14 @@
     @Test
     @SmallTest
     public void testPaneSwitcherIndex() {
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertEquals(-1, mModel.get(PANE_SWITCHER_INDEX));
 
         mFocusedPaneSupplier.set(mTabSwitcherPane);
@@ -300,7 +355,14 @@
     @Test
     @SmallTest
     public void testMenuButtonVisibility() {
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         when(mIncognitoTabSwitcherPane.getMenuButtonVisible()).thenReturn(false);
         mFocusedPaneSupplier.set(mIncognitoTabSwitcherPane);
         assertFalse(mModel.get(MENU_BUTTON_VISIBLE));
@@ -318,7 +380,13 @@
     public void testPaneButtonLookupCallback() {
         HubToolbarMediator mediator =
                 new HubToolbarMediator(
-                        mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+                        mActivity,
+                        mModel,
+                        mPaneManager,
+                        mTracker,
+                        mSearchActivityClient,
+                        mCurrentTabSupplier,
+                        mExitHubRunnable);
         assertEquals(2, mModel.get(PANE_SWITCHER_BUTTON_DATA).size());
         assertNull(mediator.getButton(PaneId.TAB_SWITCHER));
 
@@ -340,7 +408,14 @@
                 .thenReturn(ImmutableSet.of(PaneId.TAB_SWITCHER, PaneId.TAB_GROUPS));
         when(mPaneManager.getPaneForId(PaneId.TAB_GROUPS)).thenReturn(mTabSwitcherPane);
 
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         List<FullButtonData> paneSwitcherButtonData = mModel.get(PANE_SWITCHER_BUTTON_DATA);
         assertEquals(2, paneSwitcherButtonData.size());
 
@@ -356,7 +431,14 @@
     @Test
     @SmallTest
     public void testIsCurrentPaneIncognito() {
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         mFocusedPaneSupplier.set(mTabSwitcherPane);
         assertFalse(mModel.get(IS_INCOGNITO));
         mFocusedPaneSupplier.set(mIncognitoTabSwitcherPane);
@@ -375,7 +457,9 @@
                 mModel,
                 mPaneManager,
                 mTracker,
-                mSearchActivityClient);
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertTrue(mModel.get(SEARCH_BOX_VISIBLE));
         assertFalse(mModel.get(SEARCH_LOUPE_VISIBLE));
         assertNotNull(mModel.get(SEARCH_LISTENER));
@@ -388,7 +472,14 @@
 
         when(mTabSwitcherPane.getPaneId()).thenReturn(PaneId.TAB_SWITCHER);
         mFocusedPaneSupplier.set(mTabSwitcherPane);
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertFalse(mModel.get(SEARCH_BOX_VISIBLE));
         assertTrue(mModel.get(SEARCH_LOUPE_VISIBLE));
         assertNotNull(mModel.get(SEARCH_LISTENER));
@@ -404,7 +495,9 @@
                 mModel,
                 mPaneManager,
                 mTracker,
-                mSearchActivityClient);
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertFalse(mModel.get(APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION));
         assertTrue(mModel.get(SEARCH_BOX_VISIBLE));
         assertFalse(mModel.get(SEARCH_LOUPE_VISIBLE));
@@ -429,7 +522,14 @@
 
         when(mTabSwitcherPane.getPaneId()).thenReturn(PaneId.TAB_SWITCHER);
         mFocusedPaneSupplier.set(mTabSwitcherPane);
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertFalse(mModel.get(SEARCH_BOX_VISIBLE));
         assertTrue(mModel.get(SEARCH_LOUPE_VISIBLE));
 
@@ -453,7 +553,9 @@
                 mModel,
                 mPaneManager,
                 mTracker,
-                mSearchActivityClient);
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertTrue(mModel.get(SEARCH_BOX_VISIBLE));
         assertFalse(mModel.get(SEARCH_LOUPE_VISIBLE));
         assertNotNull(mModel.get(SEARCH_LISTENER));
@@ -484,7 +586,14 @@
     public void testSearchBox_ClickListener_Tablet() {
         mConfiguration.screenWidthDp = WIDE_SCREEN_WIDTH_DP;
         mFocusedPaneSupplier.set(mTabSwitcherPane);
-        new HubToolbarMediator(mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
         assertFalse(mModel.get(SEARCH_BOX_VISIBLE));
         assertTrue(mModel.get(SEARCH_LOUPE_VISIBLE));
         assertNotNull(mModel.get(SEARCH_LISTENER));
@@ -512,6 +621,77 @@
 
     @Test
     @SmallTest
+    public void testBackButton_Phone() {
+        mConfiguration.screenWidthDp = NARROW_SCREEN_WIDTH_DP;
+        mFocusedPaneSupplier.set(mTabSwitcherPane);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
+        assertFalse(mModel.get(BACK_BUTTON_VISIBLE));
+    }
+
+    @Test
+    @SmallTest
+    public void testBackButton_Tablet() {
+        mConfiguration.screenWidthDp = WIDE_SCREEN_WIDTH_DP;
+        mFocusedPaneSupplier.set(mTabSwitcherPane);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
+        assertTrue(mModel.get(BACK_BUTTON_VISIBLE));
+    }
+
+    @Test
+    @SmallTest
+    public void testBackButton_Enabled() {
+        mFocusedPaneSupplier.set(mTabSwitcherPane);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
+        assertFalse(mModel.get(BACK_BUTTON_ENABLED));
+
+        mCurrentTabSupplier.set(mock(Tab.class));
+        assertTrue(mModel.get(BACK_BUTTON_ENABLED));
+
+        mCurrentTabSupplier.set(null);
+        assertFalse(mModel.get(BACK_BUTTON_ENABLED));
+    }
+
+    @Test
+    @SmallTest
+    public void testBackButton_Listener() {
+        mFocusedPaneSupplier.set(mTabSwitcherPane);
+        new HubToolbarMediator(
+                mActivity,
+                mModel,
+                mPaneManager,
+                mTracker,
+                mSearchActivityClient,
+                mCurrentTabSupplier,
+                mExitHubRunnable);
+        assertNotNull(mModel.get(BACK_BUTTON_LISTENER));
+
+        mModel.get(BACK_BUTTON_LISTENER).run();
+        verify(mExitHubRunnable).run();
+    }
+
+    @Test
+    @SmallTest
     public void testSearchBox_UsesConfigurationParameterNotContext() {
         // Set up a scenario where context configuration and parameter configuration differ
         // to verify that the parameter configuration is used
@@ -524,7 +704,13 @@
         mFocusedPaneSupplier.set(mTabSwitcherPane);
         HubToolbarMediator mediator =
                 new HubToolbarMediator(
-                        mActivity, mModel, mPaneManager, mTracker, mSearchActivityClient);
+                        mActivity,
+                        mModel,
+                        mPaneManager,
+                        mTracker,
+                        mSearchActivityClient,
+                        mCurrentTabSupplier,
+                        mExitHubRunnable);
 
         // Initially should show search box (phone behavior)
         assertTrue(mModel.get(SEARCH_BOX_VISIBLE));
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarProperties.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarProperties.java
index a350fef..6afebb6 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarProperties.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarProperties.java
@@ -40,6 +40,15 @@
     public static final WritableObjectPropertyKey<Runnable> SEARCH_LISTENER =
             new WritableObjectPropertyKey<>();
 
+    public static final WritableBooleanPropertyKey BACK_BUTTON_VISIBLE =
+            new WritableBooleanPropertyKey();
+
+    public static final WritableBooleanPropertyKey BACK_BUTTON_ENABLED =
+            new WritableBooleanPropertyKey();
+
+    public static final WritableObjectPropertyKey<Runnable> BACK_BUTTON_LISTENER =
+            new WritableObjectPropertyKey<>();
+
     public static final WritableBooleanPropertyKey IS_INCOGNITO = new WritableBooleanPropertyKey();
 
     public static final WritableBooleanPropertyKey APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION =
@@ -62,6 +71,9 @@
         SEARCH_BOX_VISIBLE,
         SEARCH_LOUPE_VISIBLE,
         SEARCH_LISTENER,
+        BACK_BUTTON_VISIBLE,
+        BACK_BUTTON_ENABLED,
+        BACK_BUTTON_LISTENER,
         IS_INCOGNITO,
         APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION,
         HUB_SEARCH_ENABLED_STATE,
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
index 61d86f3..6243237 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
@@ -46,6 +46,7 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.hub.HubToolbarProperties.PaneButtonLookup;
 import org.chromium.ui.animation.AnimationHandler;
 import org.chromium.ui.interpolators.Interpolators;
@@ -61,6 +62,8 @@
     private View mSearchBoxLayout;
     private EditText mSearchBoxTextView;
     private ImageView mSearchLoupeView;
+    private ImageButton mBackButton;
+    private @Nullable View mSpacer;
     private FrameLayout mPaneSwitcherCard;
 
     private Callback<Integer> mToolbarOverviewColorSetter;
@@ -95,6 +98,9 @@
         mSearchBoxLayout = findViewById(R.id.search_box);
         mSearchBoxTextView = findViewById(R.id.search_box_text);
         mSearchLoupeView = findViewById(R.id.search_loupe);
+        mBackButton = findViewById(R.id.toolbar_back_button);
+        mSpacer = findViewById(R.id.margin_spacer);
+        updateSpacerVisibility();
     }
 
     void setMenuButtonVisible(boolean visible) {
@@ -263,6 +269,16 @@
                             ImageViewCompat.setImageTintList(mMenuButton, menuButtonColor);
                         }));
 
+        mixer.registerBlend(
+                new SingleHubViewColorBlend(
+                        PANE_COLOR_BLEND_ANIMATION_DURATION_MS,
+                        colorScheme -> HubColors.getIconColor(context, colorScheme),
+                        interpolatedColor -> {
+                            ColorStateList backButtonColor =
+                                    HubColors.getButtonColorStateList(context, interpolatedColor);
+                            ImageViewCompat.setImageTintList(mBackButton, backButtonColor);
+                        }));
+
         // We don't want to pass a method reference. Lambdas will ensure we run the most recent
         // setter.
         mixer.registerBlend(
@@ -387,6 +403,36 @@
         mSearchLoupeView.setOnClickListener(v -> searchBarListener.run());
     }
 
+    /**
+     * In the event there is no back button and the GTS update is enabled, we need to show a spacer
+     * view so that that new tab button is vertically aligned with the tabs in the tab switcher.
+     * Once the back button launches we can remove this spacer.
+     */
+    private void updateSpacerVisibility() {
+        if (mSpacer == null || !HubUtils.isGtsUpdateEnabled()) return;
+
+        boolean shouldShowSpacer = mBackButton.getVisibility() == View.GONE;
+        mSpacer.setVisibility(shouldShowSpacer ? View.VISIBLE : View.GONE);
+    }
+
+    void setBackButtonVisible(boolean visible) {
+        if (!ChromeFeatureList.sHubBackButton.isEnabled()) {
+            updateSpacerVisibility();
+            return;
+        }
+
+        mBackButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+        updateSpacerVisibility();
+    }
+
+    void setBackButtonEnabled(boolean enabled) {
+        mBackButton.setEnabled(enabled);
+    }
+
+    void setBackButtonListener(Runnable backButtonListener) {
+        mBackButton.setOnClickListener(v -> backButtonListener.run());
+    }
+
     void setToolbarColorOverviewListener(Callback<Integer> colorSetter) {
         mToolbarOverviewColorSetter = colorSetter;
     }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewBinder.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewBinder.java
index 195f55a6..ab1eb025 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewBinder.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewBinder.java
@@ -6,6 +6,9 @@
 
 import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_ENABLED;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_LISTENER;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_VISIBLE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.HUB_SEARCH_ENABLED_STATE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.MENU_BUTTON_VISIBLE;
@@ -49,6 +52,12 @@
                     model.get(APPLY_DELAY_FOR_SEARCH_BOX_ANIMATION));
         } else if (key == HUB_SEARCH_ENABLED_STATE) {
             view.setHubSearchEnabledState(model.get(HUB_SEARCH_ENABLED_STATE));
+        } else if (key == BACK_BUTTON_VISIBLE) {
+            view.setBackButtonVisible(model.get(BACK_BUTTON_VISIBLE));
+        } else if (key == BACK_BUTTON_ENABLED) {
+            view.setBackButtonEnabled(model.get(BACK_BUTTON_ENABLED));
+        } else if (key == BACK_BUTTON_LISTENER) {
+            view.setBackButtonListener(model.get(BACK_BUTTON_LISTENER));
         }
     }
 }
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java
index b6b8683..ac10ffa 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java
@@ -17,6 +17,9 @@
 import static org.mockito.Mockito.when;
 
 import static org.chromium.chrome.browser.hub.HubColorMixer.COLOR_MIXER;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_ENABLED;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_LISTENER;
+import static org.chromium.chrome.browser.hub.HubToolbarProperties.BACK_BUTTON_VISIBLE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.HUB_SEARCH_ENABLED_STATE;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.hub.HubToolbarProperties.MENU_BUTTON_VISIBLE;
@@ -35,6 +38,7 @@
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.FrameLayout;
+import android.widget.ImageButton;
 import android.widget.LinearLayout;
 
 import androidx.core.content.ContextCompat;
@@ -60,7 +64,8 @@
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRule;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.Features;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.hub.HubToolbarProperties.PaneButtonLookup;
 import org.chromium.components.browser_ui.styles.SemanticColorUtils;
@@ -111,6 +116,7 @@
     private View mSearchBox;
     private View mSearchLoupe;
     private EditText mSearchBoxText;
+    private ImageButton mBackButton;
     private PropertyModel mPropertyModel;
     private HubColorMixer mColorMixer;
 
@@ -134,6 +140,7 @@
         mSearchBox = mToolbarContainer.findViewById(R.id.search_box);
         mSearchLoupe = mToolbarContainer.findViewById(R.id.search_loupe);
         mSearchBoxText = mToolbarContainer.findViewById(R.id.search_box_text);
+        mBackButton = mToolbarContainer.findViewById(R.id.toolbar_back_button);
         mActivity.setContentView(mToolbarContainer);
 
         mFocusedPaneSupplier = new ObservableSupplierImpl<>();
@@ -261,6 +268,36 @@
     }
 
     @Test
+    @EnableFeatures({ChromeFeatureList.HUB_BACK_BUTTON})
+    public void testBackButtonVisibility() {
+        mPropertyModel.set(BACK_BUTTON_VISIBLE, false);
+        assertEquals(View.GONE, mBackButton.getVisibility());
+
+        mPropertyModel.set(BACK_BUTTON_VISIBLE, true);
+        assertEquals(View.VISIBLE, mBackButton.getVisibility());
+    }
+
+    @Test
+    public void testBackButtonEnabled() {
+        mPropertyModel.set(BACK_BUTTON_ENABLED, false);
+        assertFalse(mBackButton.isEnabled());
+
+        mPropertyModel.set(BACK_BUTTON_ENABLED, true);
+        assertTrue(mBackButton.isEnabled());
+    }
+
+    @Test
+    public void testBackButtonListener() {
+        CallbackHelper callbackHelper = new CallbackHelper();
+        Runnable testListener = callbackHelper::notifyCalled;
+
+        assertEquals(0, callbackHelper.getCallCount());
+        mPropertyModel.set(BACK_BUTTON_LISTENER, testListener);
+        mBackButton.performClick();
+        assertEquals(1, callbackHelper.getCallCount());
+    }
+
+    @Test
     public void testSearchBoxListener() {
         CallbackHelper callbackHelper = new CallbackHelper();
         Runnable testListener =
@@ -288,7 +325,7 @@
     }
 
     @Test
-    @Features.DisableFeatures({
+    @DisableFeatures({
         ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE,
     })
     public void testUpdateSearchBoxColorScheme() {
@@ -314,7 +351,7 @@
     }
 
     @Test
-    @Features.EnableFeatures({ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE})
+    @EnableFeatures({ChromeFeatureList.GRID_TAB_SWITCHER_SURFACE_COLOR_UPDATE})
     public void testUpdateSearchBoxColorScheme_gtsSurfaceColorUpdateEnabled() {
         forceSetColorScheme(HubColorScheme.INCOGNITO);
 
@@ -344,11 +381,11 @@
     }
 
     @Test
-    @Features.DisableFeatures({
+    @DisableFeatures({
         ChromeFeatureList.GRID_TAB_SWITCHER_UPDATE,
     })
     public void testHubColorMixer_searchBoxEnabled() {
-        verify(mColorMixer, times(8)).registerBlend(any());
+        verify(mColorMixer, times(9)).registerBlend(any());
     }
 
     /**
diff --git a/chrome/browser/hub/internal/android/res/layout/hub_bottom_toolbar_layout.xml b/chrome/browser/hub/internal/android/res/layout/hub_bottom_toolbar_layout.xml
new file mode 100644
index 0000000..52dfca8
--- /dev/null
+++ b/chrome/browser/hub/internal/android/res/layout/hub_bottom_toolbar_layout.xml
@@ -0,0 +1,14 @@
+<?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.
+-->
+<org.chromium.chrome.browser.hub.HubBottomToolbarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/hub_bottom_toolbar"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+</org.chromium.chrome.browser.hub.HubBottomToolbarView>
diff --git a/chrome/browser/hub/internal/android/res/layout/hub_layout.xml b/chrome/browser/hub/internal/android/res/layout/hub_layout.xml
index 19d4951d..321d5cc 100644
--- a/chrome/browser/hub/internal/android/res/layout/hub_layout.xml
+++ b/chrome/browser/hub/internal/android/res/layout/hub_layout.xml
@@ -9,13 +9,18 @@
   android:layout_height="match_parent">
 
   <LinearLayout
+    android:id="@+id/hub_main_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
 
     <include layout="@layout/hub_toolbar_layout" />
 
-    <include layout="@layout/hub_pane_host_layout" />
+    <include
+        layout="@layout/hub_pane_host_layout"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"/>
 
   </LinearLayout>
 
diff --git a/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml b/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml
index 3e1f1bc..b21e51e7 100644
--- a/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml
+++ b/chrome/browser/hub/internal/android/res/layout/hub_toolbar_layout.xml
@@ -33,13 +33,39 @@
       android:layout_width="match_parent"
       android:layout_height="@dimen/toolbar_height_no_shadow">
 
-      <Button
-        android:id="@+id/toolbar_action_button"
+      <LinearLayout
+        android:orientation="horizontal"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_gravity="start|center_vertical"
-        android:visibility="gone"
-        style="?attr/newTabButtonStyle"/>
+        android:layout_gravity="start|center_vertical">
+
+        <Space
+          android:id="@+id/margin_spacer"
+          android:layout_width="@dimen/hub_toolbar_action_button_start_margin"
+          android:layout_height="match_parent"
+          android:visibility="gone"/>
+
+        <org.chromium.ui.widget.ChromeImageButton
+          android:id="@+id/toolbar_back_button"
+          android:src="@drawable/ic_arrow_back_24dp"
+          android:layout_width="@dimen/min_touch_target_size"
+          android:layout_height="@dimen/min_touch_target_size"
+          android:layout_gravity="center"
+          android:layout_marginStart="4dp"
+          android:contentDescription="@string/back"
+          android:tooltipText="@string/back"
+          android:visibility="gone"
+          style="@style/ToolbarMenuButton"
+          app:tint="@color/default_icon_color_tint_list"/>
+
+        <Button
+          android:id="@+id/toolbar_action_button"
+          android:layout_width="wrap_content"
+          android:layout_height="match_parent"
+          android:layout_gravity="start|center_vertical"
+          android:visibility="gone"
+          style="?attr/newTabButtonStyle"/>
+      </LinearLayout>
 
       <FrameLayout
         android:id="@+id/pane_switcher_card"
@@ -82,7 +108,7 @@
             android:tooltipText="@string/accessibility_search_loupe_tooltip_text"
             style="@style/ToolbarMenuButton"
             app:tint="@color/default_icon_color_tint_list"  />
-          <include layout="@layout/menu_button" />
+        <include layout="@layout/menu_button" />
       </LinearLayout>
 
     </FrameLayout>
diff --git a/chrome/browser/hub/internal/android/res/layout/hub_xr_layout.xml b/chrome/browser/hub/internal/android/res/layout/hub_xr_layout.xml
index 8c5d18d..15b403b 100644
--- a/chrome/browser/hub/internal/android/res/layout/hub_xr_layout.xml
+++ b/chrome/browser/hub/internal/android/res/layout/hub_xr_layout.xml
@@ -9,6 +9,7 @@
   android:layout_height="match_parent">
 
   <LinearLayout
+    android:id="@+id/hub_main_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
@@ -19,7 +20,11 @@
       android:layout_height="@dimen/hub_xr_vertical_gap_between_toolbar_and_host_pane"
       android:layout_width="0dp" />
 
-    <include layout="@layout/hub_pane_host_layout" />
+    <include
+      layout="@layout/hub_pane_host_layout"
+      android:layout_width="match_parent"
+      android:layout_height="0dp"
+      android:layout_weight="1" />
 
   </LinearLayout>
 
diff --git a/chrome/browser/hub/internal/android/res/layout/hub_xr_toolbar_layout.xml b/chrome/browser/hub/internal/android/res/layout/hub_xr_toolbar_layout.xml
index ff255955..844c8f9 100644
--- a/chrome/browser/hub/internal/android/res/layout/hub_xr_toolbar_layout.xml
+++ b/chrome/browser/hub/internal/android/res/layout/hub_xr_toolbar_layout.xml
@@ -36,6 +36,19 @@
       android:layout_width="wrap_content"
       android:layout_height="@dimen/toolbar_height_no_shadow">
 
+      <org.chromium.ui.widget.ChromeImageButton
+        android:id="@+id/toolbar_back_button"
+        android:src="@drawable/ic_arrow_back_24dp"
+        android:layout_width="@dimen/min_touch_target_size"
+        android:layout_height="@dimen/min_touch_target_size"
+        android:layout_gravity="center"
+        android:layout_marginStart="4dp"
+        android:contentDescription="@string/back"
+        android:tooltipText="@string/back"
+        android:visibility="gone"
+        style="@style/ToolbarMenuButton"
+        app:tint="@color/default_icon_color_tint_list" />
+
       <Button
         android:id="@+id/toolbar_action_button"
         android:layout_width="wrap_content"
@@ -74,7 +87,7 @@
             android:tooltipText="@string/accessibility_search_loupe_tooltip_text"
             style="@style/ToolbarMenuButton"
             app:tint="@color/default_icon_color_tint_list"  />
-          <include layout="@layout/menu_button" />
+        <include layout="@layout/menu_button" />
       </LinearLayout>
 
     </LinearLayout>
diff --git a/chrome/browser/keyboard_accessory/android/BUILD.gn b/chrome/browser/keyboard_accessory/android/BUILD.gn
index b369458..5823ea0 100644
--- a/chrome/browser/keyboard_accessory/android/BUILD.gn
+++ b/chrome/browser/keyboard_accessory/android/BUILD.gn
@@ -53,7 +53,6 @@
     "//chrome/browser",
     "//chrome/browser/autofill",
     "//chrome/browser/password_manager/android:unit_tests",
-    "//chrome/browser/password_manager/android/access_loss:test_support",
     "//chrome/browser/password_manager/android/grouped_affiliations:test_utils",
     "//chrome/browser/plus_addresses",
     "//chrome/browser/ui/plus_addresses",
diff --git a/chrome/browser/keyboard_accessory/android/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java b/chrome/browser/keyboard_accessory/android/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
index f013610..a4ec3d2 100644
--- a/chrome/browser/keyboard_accessory/android/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
+++ b/chrome/browser/keyboard_accessory/android/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponent.java
@@ -258,7 +258,7 @@
      */
     void confirmDeletionOperation(
             String title,
-            String message,
+            CharSequence message,
             String confirmButtonText,
             Runnable confirmedCallback,
             Runnable declinedCallback);
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 73c45be..0180026 100644
--- a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.cc
+++ b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.cc
@@ -28,7 +28,6 @@
 #include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
 #include "chrome/browser/keyboard_accessory/android/manual_filling_utils.h"
 #include "chrome/browser/keyboard_accessory/android/password_accessory_controller.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller.h"
 #include "chrome/browser/password_manager/android/password_generation_controller.h"
@@ -389,7 +388,6 @@
             ChromePasswordManagerClient::FromWebContents(web_contents),
             base::BindRepeating(GetPasswordManagerDriver),
             std::make_unique<AcknowledgeGroupedCredentialSheetController>(),
-            std::make_unique<PasswordAccessLossWarningBridgeImpl>(),
             std::make_unique<PasswordManagerErrorMessageHelperBridgeImpl>())));
   }
 }
@@ -403,7 +401,6 @@
     PasswordDriverSupplierForFocusedFrame driver_supplier,
     std::unique_ptr<AcknowledgeGroupedCredentialSheetController>
         grouped_credential_sheet_controller,
-    std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge,
     std::unique_ptr<PasswordManagerErrorMessageHelperBridge>
         password_manager_error_message_helper_bridge) {
   DCHECK(web_contents) << "Need valid WebContents to attach controller to!";
@@ -417,7 +414,6 @@
           web_contents, credential_cache, std::move(manual_filling_controller),
           password_client, std::move(driver_supplier),
           std::move(grouped_credential_sheet_controller),
-          std::move(access_loss_warning_bridge),
           std::move(password_manager_error_message_helper_bridge))));
 }
 
@@ -630,7 +626,6 @@
     PasswordDriverSupplierForFocusedFrame driver_supplier,
     std::unique_ptr<AcknowledgeGroupedCredentialSheetController>
         grouped_credential_sheet_controller,
-    std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge,
     std::unique_ptr<PasswordManagerErrorMessageHelperBridge>
         password_manager_error_message_helper_bridge)
     : content::WebContentsObserver(web_contents),
@@ -644,7 +639,6 @@
           std::move(password_manager_error_message_helper_bridge)),
       grouped_credential_sheet_controller_(
           std::move(grouped_credential_sheet_controller)),
-      access_loss_warning_bridge_(std::move(access_loss_warning_bridge)),
       plus_address_service_(PlusAddressServiceFactory::GetForBrowserContext(
           GetWebContents().GetBrowserContext())) {}
 
@@ -920,17 +914,6 @@
           plus_addresses::hats::SurveyType::kFilledPlusAddressViaManualFallack);
     }
   }
-
-  Profile* profile =
-      Profile::FromBrowserContext(GetWebContents().GetBrowserContext());
-  if (profile && access_loss_warning_bridge_->ShouldShowAccessLossNoticeSheet(
-                     profile->GetPrefs(), /*called_at_startup=*/false)) {
-    access_loss_warning_bridge_->MaybeShowAccessLossNoticeSheet(
-        profile->GetPrefs(), GetWebContents().GetTopLevelNativeWindow(),
-        profile, /*called_at_startup=*/false,
-        password_manager_android_util::PasswordAccessLossWarningTriggers::
-            kKeyboardAcessorySheet);
-  }
 }
 
 void PasswordAccessoryControllerImpl::AllPasswordsSheetDismissed() {
diff --git a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.h b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.h
index d67610e..d589653 100644
--- a/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.h
+++ b/chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.h
@@ -15,7 +15,6 @@
 #include "chrome/browser/keyboard_accessory/android/accessory_sheet_data.h"
 #include "chrome/browser/keyboard_accessory/android/affiliated_plus_profiles_provider.h"
 #include "chrome/browser/keyboard_accessory/android/password_accessory_controller.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_helper.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller.h"
 #include "chrome/browser/password_manager/android/password_manager_error_message_helper_bridge.h"
@@ -100,8 +99,6 @@
       PasswordDriverSupplierForFocusedFrame driver_supplier,
       std::unique_ptr<AcknowledgeGroupedCredentialSheetController>
           grouped_credential_sheet_controller,
-      std::unique_ptr<PasswordAccessLossWarningBridge>
-          access_loss_warning_bridge,
       std::unique_ptr<PasswordManagerErrorMessageHelperBridge>
           password_manager_error_message_helper_bridge);
 
@@ -133,8 +130,6 @@
       PasswordDriverSupplierForFocusedFrame driver_supplier,
       std::unique_ptr<AcknowledgeGroupedCredentialSheetController>
           grouped_credential_sheet_controller,
-      std::unique_ptr<PasswordAccessLossWarningBridge>
-          access_loss_warning_bridge,
       std::unique_ptr<PasswordManagerErrorMessageHelperBridge>
           password_manager_error_message_helper_bridge);
 
@@ -312,10 +307,6 @@
   std::unique_ptr<AcknowledgeGroupedCredentialSheetController>
       grouped_credential_sheet_controller_;
 
-  // Bridge used for showing the password access loss warning sheet after
-  // filling credentials.
-  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge_;
-
   const raw_ptr<plus_addresses::PlusAddressService> plus_address_service_;
 
   std::unique_ptr<plus_addresses::AllPlusAddressesBottomSheetController>
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 46cf0f3..cc83041 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
@@ -27,7 +27,6 @@
 #include "chrome/browser/keyboard_accessory/android/accessory_sheet_enums.h"
 #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/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller_test_helper.h"
 #include "chrome/browser/password_manager/android/mock_password_manager_error_message_helper_bridge.h"
 #include "chrome/browser/password_manager/android/password_generation_controller.h"
@@ -421,10 +420,6 @@
 
   void CreateSheetController(
       security_state::SecurityLevel security_level = security_state::SECURE) {
-    auto access_loss_bridge =
-        std::make_unique<MockPasswordAccessLossWarningBridge>();
-    mock_access_loss_warning_bridge_ = access_loss_bridge.get();
-
     auto error_message_helper_bridge =
         std::make_unique<MockPasswordManagerErrorMessageHelperBridge>();
     mock_error_message_helper_bridge_ = error_message_helper_bridge.get();
@@ -435,7 +430,7 @@
         base::BindRepeating(&PasswordAccessoryControllerTest::GetBaseDriver,
                             base::Unretained(this)),
         grouped_credential_sheet_test_helper.CreateController(),
-        std::move(access_loss_bridge), std::move(error_message_helper_bridge));
+        std::move(error_message_helper_bridge));
 
     controller()->RegisterFillingSourceObserver(filling_source_observer_.Get());
     controller()->SetSecurityLevelForTesting(security_level);
@@ -494,7 +489,6 @@
       filling_source_observer_;
   AcknowledgeGroupedCredentialSheetControllerTestHelper
       grouped_credential_sheet_test_helper;
-  raw_ptr<MockPasswordAccessLossWarningBridge> mock_access_loss_warning_bridge_;
   raw_ptr<MockPasswordManagerErrorMessageHelperBridge>
       mock_error_message_helper_bridge_;
   scoped_refptr<MockPasswordStoreInterface> mock_account_password_store_;
@@ -2022,53 +2016,6 @@
           .Build());
 }
 
-TEST_F(PasswordAccessoryControllerTest,
-       ShowAccessLossWarningSheetOnFillingCredential) {
-  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
-    auto mock_authenticator = std::make_unique<MockDeviceAuthenticator>();
-    ON_CALL(*mock_authenticator, AuthenticateWithMessage)
-        .WillByDefault(
-            base::test::RunOnceCallbackRepeatedly<1>(/*auth_succeeded=*/true));
-    EXPECT_CALL(*password_client(), GetDeviceAuthenticator)
-        .WillOnce(Return(testing::ByMove(std::move(mock_authenticator))))
-        .RetiresOnSaturation();
-  }
-
-  features_.Reset();
-  features_.InitWithFeatures({plus_addresses::features::kPlusAddressesEnabled},
-                             {});
-  CreateSheetController();
-
-  // Set up credentials for filling.
-  std::vector<PasswordForm> matches = {CreateEntry(
-      "Ben", "S3cur3", GURL(kExampleSite), PasswordForm::MatchType::kExact)};
-  cache()->SaveCredentialsAndBlocklistedForOrigin(
-      matches, CredentialCache::IsOriginBlocklisted(false), std::nullopt,
-      url::Origin::Create(GURL(kExampleSite)));
-  controller()->RefreshSuggestionsForField(
-      FocusedFieldType::kFillableUsernameField,
-      /*is_field_eligible_for_manual_generation=*/false);
-  AccessorySheetField selected_field =
-      AccessorySheetField::Builder()
-          .SetSuggestionType(AccessorySuggestionType::kCredentialPassword)
-          .SetDisplayText(u"S3cur3")
-          .SetIsObfuscated(true)
-          .SetSelectable(true)
-          .Build();
-  EXPECT_CALL(*mock_access_loss_warning_bridge_,
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(
-      *mock_access_loss_warning_bridge_,
-      MaybeShowAccessLossNoticeSheet(
-          profile()->GetPrefs(), _, profile(),
-          /*called_at_startup=*/false,
-          password_manager_android_util::PasswordAccessLossWarningTriggers::
-              kKeyboardAcessorySheet));
-  controller()->OnFillingTriggered(autofill::FieldGlobalId(), selected_field);
-}
-
 TEST_F(PasswordAccessoryControllerTest, TriggersManagePlusAddress) {
   base::UserActionTester user_action_tester;
   CreateSheetController();
diff --git a/chrome/browser/media/media_engagement_preloaded_list.cc b/chrome/browser/media/media_engagement_preloaded_list.cc
index bc08f85..8b35097 100644
--- a/chrome/browser/media/media_engagement_preloaded_list.cc
+++ b/chrome/browser/media/media_engagement_preloaded_list.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media/media_engagement_preloaded_list.h"
 
 #include <cstdint>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
@@ -67,9 +63,9 @@
   }
 
   // Copy data from the protobuf message.
-  dafsa_ =
-      std::vector<uint8_t>(message.dafsa().c_str(),
-                           message.dafsa().c_str() + message.dafsa().length());
+  dafsa_ = std::vector<uint8_t>(
+      message.dafsa().c_str(),
+      UNSAFE_TODO(message.dafsa().c_str() + message.dafsa().length()));
 
   is_loaded_ = true;
   return true;
diff --git a/chrome/browser/media/router/discovery/discovery_network_list_wifi_linux.cc b/chrome/browser/media/router/discovery/discovery_network_list_wifi_linux.cc
index 5b2b0bcd..79b711c 100644
--- a/chrome/browser/media/router/discovery/discovery_network_list_wifi_linux.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_list_wifi_linux.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 "chrome/browser/media/router/discovery/discovery_network_list_wifi.h"
 
 #include <linux/wireless.h>
@@ -16,6 +11,7 @@
 #include <sys/types.h>
 
 #include "base/check.h"
+#include "base/compiler_specific.h"
 #include "base/files/scoped_file.h"
 #include "net/base/network_interfaces_linux.h"
 
@@ -34,7 +30,7 @@
     }
   }
   struct iwreq wreq = {};
-  strncpy(wreq.ifr_name, if_name.data(), IFNAMSIZ - 1);
+  UNSAFE_TODO(strncpy(wreq.ifr_name, if_name.data(), IFNAMSIZ - 1));
 
   char ssid[IW_ESSID_MAX_SIZE + 1] = {};
   wreq.u.essid.pointer = ssid;
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.cc b/chrome/browser/media/router/test/media_router_mojo_test.cc
index 3c5c2c2..fad08b8 100644
--- a/chrome/browser/media/router/test/media_router_mojo_test.cc
+++ b/chrome/browser/media/router/test/media_router_mojo_test.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 "chrome/browser/media/router/test/media_router_mojo_test.h"
 
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
 
@@ -268,8 +264,8 @@
   EXPECT_CALL(mock_cast_provider_, SendRouteBinaryMessage(kRouteId, _))
       .WillOnce([](const MediaRoute::Id& route_id,
                    const std::vector<uint8_t>& data) {
-        EXPECT_EQ(
-            0, memcmp(kBinaryMessage, &(data[0]), std::size(kBinaryMessage)));
+        UNSAFE_TODO(EXPECT_EQ(
+            0, memcmp(kBinaryMessage, &(data[0]), std::size(kBinaryMessage))));
       });
 
   router()->SendRouteBinaryMessage(kRouteId, std::move(expected_binary_data));
diff --git a/chrome/browser/media/webrtc/current_tab_desktop_media_list.cc b/chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
index 039bef1..a33d9ac 100644
--- a/chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/current_tab_desktop_media_list.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media/webrtc/current_tab_desktop_media_list.h"
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/hash/hash.h"
 #include "base/task/bind_post_task.h"
@@ -40,8 +36,8 @@
   std::optional<gfx::ImageSkia> image;
 
   // Only scale and update if the frame appears to be new.
-  const uint32_t hash = base::FastHash(base::span(
-      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize()));
+  const uint32_t hash = base::FastHash(UNSAFE_TODO(base::span(
+      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize())));
   if (!last_hash.has_value() || hash != last_hash.value()) {
     image = ScaleBitmap(bitmap, thumbnail_size);
   }
diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.cc b/chrome/browser/media/webrtc/desktop_media_list_base.cc
index a82e0b1a..1f25e83 100644
--- a/chrome/browser/media/webrtc/desktop_media_list_base.cc
+++ b/chrome/browser/media/webrtc/desktop_media_list_base.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media/webrtc/desktop_media_list_base.h"
 
 #include <set>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/hash/hash.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
@@ -229,8 +225,8 @@
 uint32_t DesktopMediaListBase::GetImageHash(const gfx::Image& image) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   SkBitmap bitmap = image.AsBitmap();
-  return base::FastHash(base::span(static_cast<uint8_t*>(bitmap.getPixels()),
-                                   bitmap.computeByteSize()));
+  return base::FastHash(UNSAFE_TODO(base::span(
+      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize())));
 }
 
 void DesktopMediaListBase::OnRefreshComplete() {
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_utils.cc b/chrome/browser/media/webrtc/desktop_media_picker_utils.cc
index 2b444cd..a15470dd 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_utils.cc
+++ b/chrome/browser/media/webrtc/desktop_media_picker_utils.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media/webrtc/desktop_media_picker_utils.h"
 
+#include "base/compiler_specific.h"
 #include "base/notreached.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "media/base/video_util.h"
@@ -36,7 +32,8 @@
   uint8_t* pixels_data = reinterpret_cast<uint8_t*>(result.getPixels());
   for (int y = 0; y < result.height(); ++y) {
     for (int x = 0; x < result.width(); ++x) {
-      pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] =
+      UNSAFE_TODO(
+          pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3]) =
           0xff;
     }
   }
diff --git a/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc b/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc
index 4f4c2b8..1b23a14 100644
--- a/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc
+++ b/chrome/browser/media/webrtc/multi_capture/multi_capture_usage_indicator_service.cc
@@ -53,9 +53,11 @@
     "multi-capture-login-privacy-indicators";
 const char kPrivacyIndicatorsMultiCaptureLoginNotifierId[] =
     "multi-capture-login-privacy-indicators";
-const char kPrivacyIndicatorsMultiCaptureActiveNotificationIdBase[] =
+const char kPrivacyIndicatorsMultiCaptureNotificationIdPrefix[] =
     "multi-capture-active-privacy-indicators-";
 
+constexpr auto kNotifierType = message_center::NotifierType::SYSTEM_COMPONENT;
+
 std::vector<std::string> GetAllCaptureWithNotificationApps(
     const MultiCaptureUsageIndicatorService::AllowListedAppNames& apps) {
   std::vector<std::string> capturing_apps_with_notification;
@@ -87,7 +89,7 @@
 }
 
 std::string GenerateActiveNotifcationId(const webapps::AppId& app_id) {
-  return kPrivacyIndicatorsMultiCaptureActiveNotificationIdBase + app_id;
+  return kPrivacyIndicatorsMultiCaptureNotificationIdPrefix + app_id;
 }
 
 std::vector<std::string> GenerateAppNameList(
@@ -223,8 +225,7 @@
   // popup).
   optional_fields.priority = message_center::LOW_PRIORITY;
   optional_fields.pinned = true;
-  // TODO(crbug.com/424102053): Replace with finalized icon.
-  optional_fields.vector_small_image = &vector_icons::kScreenShareIcon;
+  optional_fields.vector_small_image = &vector_icons::kScreenRecordIcon;
 
   optional_fields.buttons.emplace_back(
       l10n_util::GetStringUTF16(IDS_MULTI_CAPTURE_NOTIFICATION_BUTTON_TEXT));
@@ -240,8 +241,7 @@
       /*display_source=*/std::u16string(),
       /*origin_url=*/GURL(),
       message_center::NotifierId(
-          message_center::NotifierType::SYSTEM_COMPONENT,
-          kPrivacyIndicatorsMultiCaptureLoginNotifierId,
+          kNotifierType, kPrivacyIndicatorsMultiCaptureLoginNotifierId,
           ash::NotificationCatalogName::kPrivacyIndicators),
       optional_fields,
       /*delegate=*/
@@ -283,8 +283,7 @@
     // Using this notifier ID will tie the notification to the privacy
     // indicators group and prevent a separate icon to show up in the system
     // tray.
-    // TODO(crbug.com/432201381): Create multi capture specific notifier id.
-    notifier_id = ash::kPrivacyIndicatorsNotifierId;
+    notifier_id = ash::kPrivacyIndicatorsMultiCaptureNotifierId;
   }
 
   if (notification_shown_for_app_id_.contains(app_id)) {
@@ -293,8 +292,7 @@
     optional_fields.priority = message_center::LOW_PRIORITY;
   }
 
-  // TODO(crbug.com/424102053): Replace with finalized icon.
-  optional_fields.vector_small_image = &vector_icons::kScreenShareIcon;
+  optional_fields.vector_small_image = &vector_icons::kScreenRecordIcon;
   optional_fields.pinned = true;
 
   message_center::Notification notification(
@@ -312,7 +310,7 @@
       /*display_source=*/std::u16string(),
       /*origin_url=*/GURL(),
       message_center::NotifierId(
-          message_center::NotifierType::SYSTEM_COMPONENT, notifier_id,
+          kNotifierType, notifier_id,
           ash::NotificationCatalogName::kPrivacyIndicators),
       optional_fields,
       // TODO(crbug.com/424104858): Make the notification do nothing on click.
@@ -458,7 +456,6 @@
     // and only execute this if there is a change.
     notification_display_service_->Close(NotificationHandler::Type::TRANSIENT,
                                          GenerateActiveNotifcationId(app_id));
-
     notification_display_service_->Display(
         NotificationHandler::Type::TRANSIENT,
         CreateActiveCaptureNotification(app_id, app_name,
diff --git a/chrome/browser/media/webrtc/tab_desktop_media_list.cc b/chrome/browser/media/webrtc/tab_desktop_media_list.cc
index fa393d8..8e04328c 100644
--- a/chrome/browser/media/webrtc/tab_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/tab_desktop_media_list.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media/webrtc/tab_desktop_media_list.h"
 
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/containers/adapters.h"
 #include "base/functional/bind.h"
 #include "base/hash/hash.h"
@@ -82,8 +78,8 @@
   gfx::ImageSkia image;
 
   // Only scale and update if the frame appears to be new.
-  const uint32_t hash = base::FastHash(base::span(
-      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize()));
+  const uint32_t hash = base::FastHash(UNSAFE_TODO(base::span(
+      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize())));
   if (!last_hash.has_value() || hash != last_hash.value()) {
     image = ScaleBitmap(bitmap, desktopcapture::kPreviewSize);
   }
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_history.cc b/chrome/browser/media/webrtc/webrtc_event_log_history.cc
index 9bfc5f7..1a72a60 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_history.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_history.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media/webrtc/webrtc_event_log_history.h"
 
 #include <limits>
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -314,7 +310,8 @@
 
   std::string file_contents;
   file_contents.resize(kMaxHistoryFileSizeBytes);
-  const int read_bytes = file.Read(0, &file_contents[0], file_contents.size());
+  const int read_bytes =
+      UNSAFE_TODO(file.Read(0, &file_contents[0], file_contents.size()));
   if (read_bytes < 0) {
     LOG(WARNING) << "Couldn't read contents of history file.";
     return false;
diff --git a/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc b/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc
index b6eefee..3b36b28 100644
--- a/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.cc
+++ b/chrome/browser/media/webrtc/webrtc_rtp_dump_writer.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 "chrome/browser/media/webrtc/webrtc_rtp_dump_writer.h"
 
 #include <string.h>
 
+#include "base/compiler_specific.h"
 #include "base/containers/extend.h"
 #include "base/containers/span.h"
 #include "base/containers/span_writer.h"
@@ -89,7 +85,7 @@
   explicit FileWorker(const base::FilePath& dump_path) : dump_path_(dump_path) {
     DETACH_FROM_SEQUENCE(sequence_checker_);
 
-    memset(&stream_, 0, sizeof(stream_));
+    UNSAFE_TODO(memset(&stream_, 0, sizeof(stream_)));
     int result = deflateInit2(&stream_,
                               Z_DEFAULT_COMPRESSION,
                               Z_DEFLATED,
@@ -219,7 +215,7 @@
 
     output_buffer.resize(output_buffer.size() - stream_.avail_out);
 
-    memset(&stream_, 0, sizeof(z_stream));
+    UNSAFE_TODO(memset(&stream_, 0, sizeof(z_stream)));
 
     DCHECK(!output_buffer.empty());
     return base::AppendToFile(dump_path_, output_buffer);
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
index d3bf45d..c8bcb98 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
 
 #include <string>
 #include <string_view>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/files/safe_base_name.h"
@@ -199,7 +195,7 @@
   char buffer[net::kMaxBytesToSniff];
 
   // Read as much as net::SniffMimeTypeFromLocalData() will bother looking at.
-  int64_t len = file.Read(0, buffer, net::kMaxBytesToSniff);
+  int64_t len = UNSAFE_TODO(file.Read(0, buffer, net::kMaxBytesToSniff));
   if (len < 0)
     return base::File::FILE_ERROR_FAILED;
 
diff --git a/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc b/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc
index c1fcb2f..820841f 100644
--- a/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.cc
+++ b/chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/numerics/safe_conversions.h"
 #include "net/base/io_buffer.h"
@@ -81,8 +77,8 @@
 
     int copy_len = std::min(source_buffer->BytesRemaining(),
                             sink->BytesRemaining());
-    std::copy(source_buffer->data(), source_buffer->data() + copy_len,
-              sink->data());
+    std::copy(source_buffer->data(),
+              UNSAFE_TODO(source_buffer->data() + copy_len), sink->data());
 
     source_buffer->DidConsume(copy_len);
     sink->DidConsume(copy_len);
diff --git a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
index 3d5b0b8..3a0913d 100644
--- a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
+++ b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/media_galleries/fileapi/supported_image_type_validator.h"
 
 #include <memory>
 #include <utility>
 
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/files/file.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -49,7 +45,8 @@
 
   result = std::make_unique<std::string>();
   result->resize(file_info.size);
-  if (file.Read(0, std::data(*result), file_info.size) != file_info.size) {
+  if (UNSAFE_TODO(file.Read(0, std::data(*result), file_info.size)) !=
+      file_info.size) {
     result.reset();
   }
 
diff --git a/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service.cc b/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service.cc
index 4392b0b..021d3652 100644
--- a/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service.cc
+++ b/chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service.cc
@@ -27,7 +27,6 @@
       password_metrics_recorder_(
           std::make_unique<
               password_manager::PasswordSessionDurationsMetricsRecorder>(
-              pref_service,
               sync_service)) {
   session_duration_observation_.Observe(tracker);
   if (tracker->in_session()) {
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
index 11a707e..0a4ec052 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_preconnect_client_browsertest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/predictors/loading_predictor.h"
 #include "chrome/browser/predictors/loading_predictor_factory.h"
 #include "chrome/browser/predictors/preconnect_manager.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
 #include "chrome/browser/ui/browser.h"
@@ -136,6 +137,10 @@
   mojo::Remote<network::mojom::ConnectionChangeObserverClient> observer_;
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<base::RunLoop> run_loop_;
 };
diff --git a/chrome/browser/net/cert_verifier_policy_browsertest.cc b/chrome/browser/net/cert_verifier_policy_browsertest.cc
index e8a3a65..214fd883 100644
--- a/chrome/browser/net/cert_verifier_policy_browsertest.cc
+++ b/chrome/browser/net/cert_verifier_policy_browsertest.cc
@@ -50,7 +50,6 @@
 #include "chrome/browser/net/server_certificate_database_service_factory.h"  // nogncheck
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/server_certificate_database/server_certificate_database.h"  // nogncheck
@@ -65,7 +64,7 @@
   // In some cases, we may need to wait until the certificate policy updates
   // propagate.
   void UpdateProviderPolicyAndWaitForUpdate(const policy::PolicyMap& policies) {
-    // If features::kEnableCertManagementUIV2Write is enabled, the cert verifier
+    // If the ServerCertificateDatabaseService is enabled, the cert verifier
     // service update is asynchronous and the test needs to wait for the update
     // to complete.
     // Otherwise, cert changes may not make it to the verifier in time to clear
@@ -913,14 +912,7 @@
     : public CertVerifierServicePolicyTest,
       public testing::WithParamInterface<bool> {
  public:
-  CertVerifierServicePolicyAndUserRootsTest() {
-    feature_list_.InitWithFeatures({features::kEnableCertManagementUIV2,
-                                    features::kEnableCertManagementUIV2Write},
-                                   {});
-  }
   bool add_certs() const { return GetParam(); }
-
-  base::test::ScopedFeatureList feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_P(CertVerifierServicePolicyAndUserRootsTest,
diff --git a/chrome/browser/net/cert_verifier_service_browsertest.cc b/chrome/browser/net/cert_verifier_service_browsertest.cc
index 5d5aa35..396846a9 100644
--- a/chrome/browser/net/cert_verifier_service_browsertest.cc
+++ b/chrome/browser/net/cert_verifier_service_browsertest.cc
@@ -43,7 +43,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/chrome_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/server_certificate_database/server_certificate_database.h"  // nogncheck
@@ -239,12 +238,6 @@
 
 class CertVerifierUserSettingsTest : public PlatformBrowserTest {
  public:
-  CertVerifierUserSettingsTest() {
-    feature_list_.InitWithFeatures({features::kEnableCertManagementUIV2,
-                                    features::kEnableCertManagementUIV2Write},
-                                   {});
-  }
-
   testing::AssertionResult AddCertificateToDatabaseAndWaitForVerifierUpdate(
       net::ServerCertificateDatabase::CertInformation cert_info) {
     return AddCertificateToProfileDatabaseAndWaitForVerifierUpdate(
@@ -274,9 +267,6 @@
     }
     return testing::AssertionSuccess();
   }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(CertVerifierUserSettingsTest, TestUserSettingsUsed) {
diff --git a/chrome/browser/net/key_pinning.proto b/chrome/browser/net/key_pinning.proto
index b291892..fb82f32 100644
--- a/chrome/browser/net/key_pinning.proto
+++ b/chrome/browser/net/key_pinning.proto
@@ -18,8 +18,8 @@
   // Optional set of forbidden SPKIs hashes, represented as the SHA256 of the
   // public key.
   repeated bytes bad_static_spki_hashes_sha256 = 3;
-  // Optional URI to send bad pin reports to.
-  string report_uri = 4;
+
+  reserved 4;
 }
 
 message PinSetInfo {
@@ -44,4 +44,4 @@
   // hostname, and includes the name of the pinset that applies to it, and
   // whether it applies to subdomains.
   repeated PinSetInfo host_pins = 4;
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index dd8e53ba..fa4b9dc0 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -466,22 +466,20 @@
 #endif
 
 #if BUILDFLAG(CHROME_ROOT_STORE_CERT_MANAGEMENT_UI)
-  if (base::FeatureList::IsEnabled(features::kEnableCertManagementUIV2Write)) {
-    // Register observer to update certificates when changes are made to the
-    // server cert database. Unretained is safe as the
-    // `server_cert_database_observer_` is a CallbackListSubscription which
-    // will unregister the observer once the ProfileNetworkContextService is
-    // destroyed.
-    net::ServerCertificateDatabaseService* server_cert_db_service =
-        net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
-            profile_);
-    // The service can be null for AshInternals profiles.
-    if (server_cert_db_service) {
-      server_cert_database_observer_ =
-          server_cert_db_service->AddObserver(base::BindRepeating(
-              &ProfileNetworkContextService::UpdateAdditionalCertificates,
-              base::Unretained(this)));
-    }
+  // Register observer to update certificates when changes are made to the
+  // server cert database. Unretained is safe as the
+  // `server_cert_database_observer_` is a CallbackListSubscription which
+  // will unregister the observer once the ProfileNetworkContextService is
+  // destroyed.
+  net::ServerCertificateDatabaseService* server_cert_db_service =
+      net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
+          profile_);
+  // The service can be null for AshInternals profiles.
+  if (server_cert_db_service) {
+    server_cert_database_observer_ =
+        server_cert_db_service->AddObserver(base::BindRepeating(
+            &ProfileNetworkContextService::UpdateAdditionalCertificates,
+            base::Unretained(this)));
   }
 #endif
 
@@ -843,19 +841,17 @@
   CHECK(!is_shutting_down_);
 
 #if BUILDFLAG(CHROME_ROOT_STORE_CERT_MANAGEMENT_UI)
-  if (base::FeatureList::IsEnabled(features::kEnableCertManagementUIV2Write)) {
-    net::ServerCertificateDatabaseService* cert_db_service =
-        net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
-            profile_);
-    // The service can be null for AshInternals profiles. If it's null, fall
-    // through to updating the additional certs without it.
-    if (cert_db_service) {
-      cert_db_service->GetAllCertificates(
-          base::BindOnce(&ProfileNetworkContextService::
-                             UpdateAdditionalCertificatesWithUserAddedCerts,
-                         weak_factory_.GetWeakPtr()));
-      return;
-    }
+  net::ServerCertificateDatabaseService* cert_db_service =
+      net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
+          profile_);
+  // The service can be null for AshInternals profiles. If it's null, fall
+  // through to updating the additional certs without it.
+  if (cert_db_service) {
+    cert_db_service->GetAllCertificates(
+        base::BindOnce(&ProfileNetworkContextService::
+                           UpdateAdditionalCertificatesWithUserAddedCerts,
+                       weak_factory_.GetWeakPtr()));
+    return;
   }
 #endif
   profile_->ForEachLoadedStoragePartition(
@@ -1141,21 +1137,17 @@
         std::move(certs)));
   }
 
-  // Intermediates from NSS are used unconditionally. There are 2 reasons why
-  // the NSS source is used:
-  // 1) If the ServerCertificateDatabase feature is not enabled
-  // (kEnableCertManagementUIV2Write is false), user-added intermediates
-  // still come from NSS, so checking NSS is required.
-  // 2) Device-wide ONC intermediate certificates may be needed as well. It's
-  // unclear if the use of device-wide policy in non-signin-profile client cert
-  // verification was intended or just an accidental side effect of NSS state
-  // being global, but enterprises might be depending on it (at least one
-  // browser_test depends on it:
+  // Intermediates from NSS are used unconditionally as device-wide ONC
+  // intermediate certificates may be needed. It's unclear if the use of
+  // device-wide policy in non-signin-profile client cert verification was
+  // intended or just an accidental side effect of NSS state being global, but
+  // enterprises might be depending on it (at least one browser_test depends on
+  // it:
   // SuccessViaCaAndIntermediate/SigninFrameWebviewClientCertsLoginTest.LockscreenTest/0).
-  // TODO(https://crbug.com/40554868): once kEnableCertManagementUIV2Write has
-  // fully launched, consider removing the NSS source and making this read from
-  // the device ONC policy directly (or decide if using the device ONC policy
-  // here is not intended and change the test to not do that).
+  // TODO(https://crbug.com/40554868): consider removing the NSS source and
+  // making this read from the device ONC policy directly, or decide if using
+  // the device ONC policy here is not intended and remove and change the test
+  // to not do that.
   sources.push_back(
       std::make_unique<net::ClientCertStoreNSS::IssuerSourceNSS>());
 
@@ -1164,19 +1156,16 @@
 
 void ProfileNetworkContextService::CreateClientCertIssuerSources(
     net::ClientCertIssuerSourceGetterCallback callback) {
-  if (base::FeatureList::IsEnabled(features::kEnableCertManagementUIV2Write)) {
-    net::ServerCertificateDatabaseService* cert_db_service =
-        net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
-            profile_);
-    // The service can be null for AshInternals profiles. If it's null fall
-    // through to creating the ClientCertIssuerSource without it.
-    if (cert_db_service) {
-      cert_db_service->GetAllCertificates(
-          base::BindOnce(&ProfileNetworkContextService::
-                             CreateClientCertIssuerSourcesWithDBCerts,
-                         weak_factory_.GetWeakPtr(), std::move(callback)));
-      return;
-    }
+  net::ServerCertificateDatabaseService* cert_db_service =
+      net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
+          profile_);
+  // The service can be null for AshInternals profiles. If it's null fall
+  // through to creating the ClientCertIssuerSource without it.
+  if (cert_db_service) {
+    cert_db_service->GetAllCertificates(base::BindOnce(
+        &ProfileNetworkContextService::CreateClientCertIssuerSourcesWithDBCerts,
+        weak_factory_.GetWeakPtr(), std::move(callback)));
+    return;
   }
 
   CreateClientCertIssuerSourcesWithDBCerts(std::move(callback),
@@ -1500,8 +1489,7 @@
   // add an isManaged() check here.
 
 #if BUILDFLAG(CHROME_ROOT_STORE_CERT_MANAGEMENT_UI)
-  if (base::FeatureList::IsEnabled(features::kEnableCertManagementUIV2Write) &&
-      net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
+  if (net::ServerCertificateDatabaseServiceFactory::GetForBrowserContext(
           profile_)) {
     cert_verifier_creation_params->wait_for_update = true;
     UpdateAdditionalCertificates();
diff --git a/chrome/browser/net/server_certificate_database_service_factory.cc b/chrome/browser/net/server_certificate_database_service_factory.cc
index 231139a..2daefb0d 100644
--- a/chrome/browser/net/server_certificate_database_service_factory.cc
+++ b/chrome/browser/net/server_certificate_database_service_factory.cc
@@ -4,9 +4,7 @@
 
 #include "chrome/browser/net/server_certificate_database_service_factory.h"
 
-#include "base/feature_list.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_features.h"
 #include "components/server_certificate_database/server_certificate_database_service.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -65,23 +63,19 @@
     ServerCertificateDatabaseServiceFactory()
     : ProfileKeyedServiceFactory(
           "ServerCertificateDatabaseService",
-          base::FeatureList::IsEnabled(
-              ::features::kEnableCertManagementUIV2Write)
-              ?
-              // Use the same service for incognito profiles.
-              ProfileSelections::Builder()
-                  .WithRegular(ProfileSelection::kRedirectedToOriginal)
-                  // For Guest the need for these these are based off of what
-                  // ProfileNetworkContextService does.
-                  .WithGuest(ProfileSelection::kRedirectedToOriginal)
-                  // Not needed for Ash internals as it's not a real user
-                  // profile and so there isn't a user to use the database.
-                  // This also matches the practical behavior of
-                  // NssServiceFactory which will end up crashing the browser
-                  // if attempted to use on an AshInternals profile.
-                  .WithAshInternals(ProfileSelection::kNone)
-                  .Build()
-              : ProfileSelections::BuildNoProfilesSelected()
+          // Use the same service for incognito profiles.
+          ProfileSelections::Builder()
+              .WithRegular(ProfileSelection::kRedirectedToOriginal)
+              // For Guest the need for these these are based off of what
+              // ProfileNetworkContextService does.
+              .WithGuest(ProfileSelection::kRedirectedToOriginal)
+              // Not needed for Ash internals as it's not a real user
+              // profile and so there isn't a user to use the database.
+              // This also matches the practical behavior of
+              // NssServiceFactory which will end up crashing the browser
+              // if attempted to use on an AshInternals profile.
+              .WithAshInternals(ProfileSelection::kNone)
+              .Build()
 
       ) {
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/new_tab_page/chrome_colors/generate_colors_info.cc b/chrome/browser/new_tab_page/chrome_colors/generate_colors_info.cc
index c58c398..f7e15b4 100644
--- a/chrome/browser/new_tab_page/chrome_colors/generate_colors_info.cc
+++ b/chrome/browser/new_tab_page/chrome_colors/generate_colors_info.cc
@@ -2,12 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "base/base64.h"
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -97,6 +93,6 @@
 }
 
 int main(int argc, char* argv[]) {
-  GenerateColorsInfoFile(argv[1]);
+  GenerateColorsInfoFile(UNSAFE_TODO(argv[1]));
   return 0;
 }
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/BUILD.gn b/chrome/browser/new_tab_page/modules/v2/tab_groups/BUILD.gn
new file mode 100644
index 0000000..223010e
--- /dev/null
+++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/BUILD.gn
@@ -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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+  sources = [ "tab_groups.mojom" ]
+
+  webui_module_path = ""
+
+  public_deps = [
+    "//mojo/public/mojom/base",
+    "//ui/base/mojom",
+    "//url/mojom:url_mojom_gurl",
+  ]
+}
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/OWNERS b/chrome/browser/new_tab_page/modules/v2/tab_groups/OWNERS
new file mode 100644
index 0000000..61b5e28
--- /dev/null
+++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
\ No newline at end of file
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom
new file mode 100644
index 0000000..43071cfe
--- /dev/null
+++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom
@@ -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.
+
+module ntp.tab_groups.mojom;
+
+import "url/mojom/url.mojom";
+
+// Information about a tab group.
+struct TabGroup {
+  // Title of the tab group.
+  string title;
+  // Url to open the tab group.
+  url.mojom.Url url;
+};
+
+// Browser-side handler for requests from NTP Module UI.
+interface PageHandler {
+  // Returns a list of most recently used tab groups.
+  GetTabGroups() => (array<TabGroup> tab_groups);
+};
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc
new file mode 100644
index 0000000..c1b8ce8
--- /dev/null
+++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.cc
@@ -0,0 +1,44 @@
+// 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 "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/search/ntp_features.h"
+#include "content/public/browser/web_contents.h"
+
+TabGroupsPageHandler::TabGroupsPageHandler(
+    mojo::PendingReceiver<ntp::tab_groups::mojom::PageHandler>
+        pending_page_handler,
+    content::WebContents* web_contents)
+    : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
+      web_contents_(web_contents),
+      page_handler_(this, std::move(pending_page_handler)) {
+  DCHECK(profile_);
+  DCHECK(web_contents_);
+}
+
+TabGroupsPageHandler::~TabGroupsPageHandler() = default;
+
+void TabGroupsPageHandler::GetTabGroups(GetTabGroupsCallback callback) {
+  const std::string data_type_param = base::GetFieldTrialParamValueByFeature(
+      ntp_features::kNtpTabGroupsModule,
+      ntp_features::kNtpTabGroupsModuleDataParam);
+  std::vector<ntp::tab_groups::mojom::TabGroupPtr> tab_groups_mojom;
+
+  if (data_type_param.find("Fake Data") != std::string::npos) {
+    // Generate fake data.
+    const int kSampleTabGroupsCount = 4;
+    for (int i = 0; i < kSampleTabGroupsCount; ++i) {
+      auto tab_group = ntp::tab_groups::mojom::TabGroup::New();
+      tab_group->title = "Tab Group " + base::NumberToString(i + 1);
+      tab_group->url = GURL("https://www.google.com");
+      tab_groups_mojom.push_back(std::move(tab_group));
+    }
+  }
+
+  std::move(callback).Run(std::move(tab_groups_mojom));
+}
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h
new file mode 100644
index 0000000..3be7755d
--- /dev/null
+++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h
@@ -0,0 +1,41 @@
+// 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 CHROME_BROWSER_NEW_TAB_PAGE_MODULES_V2_TAB_GROUPS_TAB_GROUPS_PAGE_HANDLER_H_
+#define CHROME_BROWSER_NEW_TAB_PAGE_MODULES_V2_TAB_GROUPS_TAB_GROUPS_PAGE_HANDLER_H_
+
+#include "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+class Profile;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+class TabGroupsPageHandler : public ntp::tab_groups::mojom::PageHandler {
+ public:
+  explicit TabGroupsPageHandler(
+      mojo::PendingReceiver<ntp::tab_groups::mojom::PageHandler>
+          pending_page_handler,
+      content::WebContents* web_contents);
+  ~TabGroupsPageHandler() override;
+
+  TabGroupsPageHandler(const TabGroupsPageHandler&) = delete;
+  TabGroupsPageHandler& operator=(const TabGroupsPageHandler&) = delete;
+
+  // ntp::tab_groups::mojom::PageHandler:
+  void GetTabGroups(GetTabGroupsCallback callback) override;
+
+ private:
+  raw_ptr<Profile> profile_;
+  raw_ptr<content::WebContents> web_contents_;
+
+  mojo::Receiver<ntp::tab_groups::mojom::PageHandler> page_handler_;
+
+  base::WeakPtrFactory<TabGroupsPageHandler> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_NEW_TAB_PAGE_MODULES_V2_TAB_GROUPS_TAB_GROUPS_PAGE_HANDLER_H_
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc
new file mode 100644
index 0000000..0e28817
--- /dev/null
+++ b/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc
@@ -0,0 +1,74 @@
+// 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 "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/search/ntp_features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TabGroupsPageHandlerTest : public ChromeRenderViewHostTestHarness {
+ public:
+  TabGroupsPageHandlerTest() = default;
+
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+
+    handler_ = std::make_unique<TabGroupsPageHandler>(
+        mojo::PendingReceiver<ntp::tab_groups::mojom::PageHandler>(),
+        web_contents());
+  }
+
+  void TearDown() override {
+    handler_.reset();
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
+  // Synchronously fetches tab groups data from
+  // `TabGroupsPageHandler::GetTabGroups()`. The actual mojo call is async, and
+  // this helper blocks the current thread until the page handler responds to
+  // achieve synchronization.
+  std::vector<ntp::tab_groups::mojom::TabGroupPtr> RunGetTabGroups() {
+    std::vector<ntp::tab_groups::mojom::TabGroupPtr> tab_groups_mojom;
+    base::RunLoop wait_loop;
+    handler_->GetTabGroups(base::BindOnce(
+        [](base::OnceClosure stop_waiting,
+           std::vector<ntp::tab_groups::mojom::TabGroupPtr>* tab_groups,
+           std::vector<ntp::tab_groups::mojom::TabGroupPtr> tab_groups_arg) {
+          *tab_groups = std::move(tab_groups_arg);
+          std::move(stop_waiting).Run();
+        },
+        wait_loop.QuitClosure(), &tab_groups_mojom));
+    wait_loop.Run();
+    return tab_groups_mojom;
+  }
+
+  TabGroupsPageHandler* handler() { return handler_.get(); }
+
+ private:
+  mojo::PendingRemote<ntp::tab_groups::mojom::PageHandler> page_handler_remote_;
+  std::unique_ptr<TabGroupsPageHandler> handler_;
+};
+
+TEST_F(TabGroupsPageHandlerTest, GetFakeTabGroups) {
+  // Enable the feature and set the parameter to "Fake Data".
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      ntp_features::kNtpTabGroupsModule,
+      {{ntp_features::kNtpTabGroupsModuleDataParam, "Fake Data"}});
+
+  auto tab_groups_mojom = RunGetTabGroups();
+
+  ASSERT_FALSE(tab_groups_mojom.empty());
+  int num_tab_groups = static_cast<int>(tab_groups_mojom.size());
+  for (int i = 0; i < num_tab_groups; ++i) {
+    auto& tab_group = tab_groups_mojom[i];
+    ASSERT_EQ("Tab Group " + base::NumberToString(i + 1), tab_group->title);
+    ASSERT_EQ(GURL("https://www.google.com"), tab_group->url);
+  }
+}
diff --git a/chrome/browser/new_tab_page/promos/promo_service.cc b/chrome/browser/new_tab_page/promos/promo_service.cc
index 0706c75..5be9001 100644
--- a/chrome/browser/new_tab_page/promos/promo_service.cc
+++ b/chrome/browser/new_tab_page/promos/promo_service.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 "chrome/browser/new_tab_page/promos/promo_service.h"
 
 #include <utility>
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc
index 91b7ec6f..2305093 100644
--- a/chrome/browser/notifications/notification_platform_bridge_android.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -112,7 +112,7 @@
     env->SetObjectArrayElement(actions, i, action_info.obj());
   }
 
-  return ScopedJavaLocalRef<jobjectArray>(env, actions);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, actions);
 }
 
 constexpr jint NotificationTypeToJava(
diff --git a/chrome/browser/notifications/notification_suspender_android.cc b/chrome/browser/notifications/notification_suspender_android.cc
index b817e2e..ea028b4b 100644
--- a/chrome/browser/notifications/notification_suspender_android.cc
+++ b/chrome/browser/notifications/notification_suspender_android.cc
@@ -32,7 +32,7 @@
 SkBitmap ExtractImage(JNIEnv* env,
                       const JavaParamRef<jobjectArray>& j_resources,
                       int index) {
-  ScopedJavaLocalRef<jobject> j_image(
+  auto j_image = ScopedJavaLocalRef<jobject>::Adopt(
       env, env->GetObjectArrayElement(j_resources.obj(), index));
   return j_image.is_null()
              ? SkBitmap()
diff --git a/chrome/browser/offline_pages/android/request_coordinator_bridge.cc b/chrome/browser/offline_pages/android/request_coordinator_bridge.cc
index 6e9fb267..861f1841 100644
--- a/chrome/browser/offline_pages/android/request_coordinator_bridge.cc
+++ b/chrome/browser/offline_pages/android/request_coordinator_bridge.cc
@@ -104,7 +104,7 @@
     env->SetObjectArrayElement(joa, i, j_save_page_request.obj());
   }
 
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 JNI_EXPORT void JNI_RequestCoordinatorBridge_SavePageLater(
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
index 9b622e5..c28ae7d 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
@@ -64,7 +64,6 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "third_party/blink/public/common/performance/largest_contentful_paint_type.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 #include "third_party/perfetto/include/perfetto/tracing/track.h"
 #include "ui/events/blink/blink_features.h"
@@ -1020,10 +1019,10 @@
 
   builder.Record(ukm::UkmRecorder::Get());
 
-  // Record last soft navigation metrics.
-  if (GetDelegate().GetSoftNavigationMetrics().count >= 1 &&
-      GetDelegate().GetSoftNavigationMetrics().navigation_id !=
-          blink::kNavigationIdDefaultValue) {
+  // Record last soft navigation metrics; note that 0 is the absent navigation
+  // id, see third_party/blink/renderer/core/timing/navigation_id_generator.h.
+  if (GetDelegate().GetSoftNavigationMetrics().count &&
+      GetDelegate().GetSoftNavigationMetrics().navigation_id) {
     RecordSoftNavigationMetrics(GetDelegate().GetUkmSourceIdForSoftNavigation(),
                                 GetDelegate().GetSoftNavigationMetrics());
   }
diff --git a/chrome/browser/password_manager/account_password_store_factory.cc b/chrome/browser/password_manager/account_password_store_factory.cc
index efba88ff..382c70d5 100644
--- a/chrome/browser/password_manager/account_password_store_factory.cc
+++ b/chrome/browser/password_manager/account_password_store_factory.cc
@@ -114,8 +114,6 @@
 
   Profile* profile = Profile::FromBrowserContext(context);
 
-  CHECK(password_manager::features_util::CanCreateAccountStore(
-      profile->GetPrefs()));
   DCHECK(!profile->IsOffTheRecord());
 
   os_crypt_async::OSCryptAsync* os_crypt_async =
@@ -171,11 +169,6 @@
 scoped_refptr<PasswordStoreInterface>
 AccountPasswordStoreFactory::GetForProfile(Profile* profile,
                                            ServiceAccessType access_type) {
-  if (!password_manager::features_util::CanCreateAccountStore(
-          profile->GetPrefs())) {
-    return nullptr;
-  }
-
   // |profile| gets always redirected to a non-Incognito profile below, so
   // Incognito & IMPLICIT_ACCESS means that incognito browsing session would
   // result in traces in the normal profile without the user knowing it.
diff --git a/chrome/browser/password_manager/android/BUILD.gn b/chrome/browser/password_manager/android/BUILD.gn
index 89a43f5..8b835111 100644
--- a/chrome/browser/password_manager/android/BUILD.gn
+++ b/chrome/browser/password_manager/android/BUILD.gn
@@ -24,8 +24,6 @@
     "login_db_deprecation_runner_factory.h",
     "password_manager_settings_service_android_impl.cc",
     "password_manager_settings_service_android_impl.h",
-    "password_manager_settings_service_android_migration_impl.cc",
-    "password_manager_settings_service_android_migration_impl.h",
   ]
 
   deps = [
@@ -53,8 +51,6 @@
   ]
 
   sources = [
-    "built_in_backend_to_android_backend_migrator.cc",
-    "built_in_backend_to_android_backend_migrator.h",
     "password_manager_lifecycle_helper.cc",
     "password_manager_lifecycle_helper.h",
     "password_manager_lifecycle_helper_impl.cc",
@@ -83,12 +79,8 @@
     "password_store_android_backend_receiver_bridge_impl.h",
     "password_store_android_local_backend.cc",
     "password_store_android_local_backend.h",
-    "password_store_backend_migration_decorator.cc",
-    "password_store_backend_migration_decorator.h",
     "password_store_empty_backend.cc",
     "password_store_empty_backend.h",
-    "password_store_proxy_backend.cc",
-    "password_store_proxy_backend.h",
     "password_sync_controller_delegate_android.cc",
     "password_sync_controller_delegate_android.h",
     "password_sync_controller_delegate_bridge.h",
@@ -138,9 +130,6 @@
     "//chrome/browser/lifetime/android:java",
     "//chrome/browser/loading_modal/android:java",
     "//chrome/browser/notifications:java",
-    "//chrome/browser/password_manager/android/access_loss:enums_java",
-    "//chrome/browser/password_manager/android/access_loss:settings_dialog_java",
-    "//chrome/browser/password_manager/android/access_loss:utils_java",
     "//chrome/browser/password_manager/android/pwm_disabled:java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/profiles/android:java",
@@ -179,7 +168,6 @@
   public_deps = [
     ":backend_interface_java",
     ":password_manager_resource_provider_java",
-    "access_loss:enums_java",
   ]
 
   srcjar_deps = [ ":jni_headers" ]
@@ -203,7 +191,6 @@
     "java/src/org/chromium/chrome/browser/password_manager/PasswordSyncControllerDelegateBridgeImpl.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/ExportFlow.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/ExportFlowInterface.java",
-    "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinator.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessReauthenticationHelper.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordListObserver.java",
     "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordManagerHandler.java",
@@ -307,7 +294,6 @@
 
   sources = [
     "java/src/org/chromium/chrome/browser/password_manager/CctPasswordSavingMetricsRecorderBridgeTest.java",
-    "java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinatorTest.java",
     "junit/src/org/chromium/chrome/browser/password_manager/ConfirmationDialogHelperTest.java",
     "junit/src/org/chromium/chrome/browser/password_manager/FakeCredentialManagerLauncherTest.java",
     "junit/src/org/chromium/chrome/browser/password_manager/FakePasswordManagerBackendSupportHelperTest.java",
@@ -346,7 +332,6 @@
     ":utils_java",
     "$google_play_services_package:google_play_services_base_java",
     "$google_play_services_package:google_play_services_basement_java",
-    "access_loss:junit",
     "account_storage_notice:junit",
     "add_username_dialog:junit",
     "bottom_sheet:junit",
@@ -360,9 +345,6 @@
     "//chrome/browser/feedback/android:internal_java",
     "//chrome/browser/flags:java",
     "//chrome/browser/loading_modal/android:java",
-    "//chrome/browser/password_manager/android/access_loss:enums_java",
-    "//chrome/browser/password_manager/android/access_loss:helper_java",
-    "//chrome/browser/password_manager/android/access_loss:utils_java",
     "//chrome/browser/password_manager/android/one_time_passwords:java",
     "//chrome/browser/password_manager/android/one_time_passwords:sms_otp_fetching_interface_java",
     "//chrome/browser/password_manager/android/pwd_migration:java",
@@ -540,11 +522,6 @@
   resources_package = "org.chromium.chrome.browser.password_manager"
 }
 
-java_cpp_enum("java_enum_srcjar") {
-  visibility = [ "//chrome/browser/password_manager/android/access_loss:*" ]
-  sources = [ "password_manager_android_util.h" ]
-}
-
 source_set("utils") {
   sources = [
     "cct_password_saving_metrics_recorder_bridge.cc",
@@ -594,7 +571,6 @@
     "all_passwords_bottom_sheet_controller_unittest.cc",
     "all_passwords_bottom_sheet_helper_unittest.cc",
     "auto_signin_first_run_dialog_android_unittest.cc",
-    "built_in_backend_to_android_backend_migrator_unittest.cc",
     "cred_man_controller_unittest.cc",
     "credential_leak_controller_android_unittest.cc",
     "fake_password_manager_lifecycle_helper.cc",
@@ -617,15 +593,12 @@
     "password_manager_error_message_delegate_unittest.cc",
     "password_manager_eviction_util_unittest.cc",
     "password_manager_settings_service_android_impl_unittest.cc",
-    "password_manager_settings_service_android_migration_impl_unittest.cc",
     "password_manager_ui_util_android_unittest.cc",
     "password_settings_updater_android_bridge_helper_impl_unittest.cc",
     "password_store_android_account_backend_unittest.cc",
     "password_store_android_backend_bridge_helper_impl_unittest.cc",
     "password_store_android_local_backend_unittest.cc",
-    "password_store_backend_migration_decorator_unittest.cc",
     "password_store_empty_backend_unittest.cc",
-    "password_store_proxy_backend_unittest.cc",
     "password_sync_controller_delegate_android_unittest.cc",
     "save_update_password_message_delegate_unittest.cc",
     "unified_password_manager_proto_utils_unittest.cc",
@@ -642,7 +615,6 @@
     "//chrome/browser/autofill",
     "//chrome/browser/keyboard_accessory/test_utils/android",
     "//chrome/browser/password_edit_dialog/android:android",
-    "//chrome/browser/password_manager/android/access_loss:test_support",
     "//chrome/browser/password_manager/android/add_username_dialog:android",
     "//chrome/browser/password_manager/factories:factories",
     "//chrome/browser/plus_addresses",
@@ -735,7 +707,6 @@
     ":shared_preferences_delegate",
     ":utils",
     ":utils_jni_headers",
-    "access_loss:public",
     "account_storage_notice",
     "add_username_dialog:android",
     "grouped_affiliations:public",
diff --git a/chrome/browser/password_manager/android/access_loss/BUILD.gn b/chrome/browser/password_manager/android/access_loss/BUILD.gn
deleted file mode 100644
index c1f6089..0000000
--- a/chrome/browser/password_manager/android/access_loss/BUILD.gn
+++ /dev/null
@@ -1,211 +0,0 @@
-import("//build/config/android/rules.gni")
-import("//third_party/jni_zero/jni_zero.gni")
-
-android_library("enums_java") {
-  srcjar_deps = [ "//chrome/browser/password_manager/android:java_enum_srcjar" ]
-
-  deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
-}
-
-android_library("utils_java") {
-  sources = [ "java/src/org/chromium/chrome/browser/access_loss/AccessLossWarningMetricsRecorder.java" ]
-
-  deps = [
-    ":enums_java",
-    "//base:base_java",
-    "//chrome/browser/flags:java",
-    "//third_party/androidx:androidx_annotation_annotation_java",
-  ]
-}
-
-android_library("helper_java") {
-  resources_package = "org.chromium.chrome.browser.access_loss"
-
-  sources = [
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossNotificationProperties.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelper.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinator.java",
-  ]
-
-  deps = [
-    ":enums_java",
-    ":utils_java",
-    "//base:base_java",
-    "//build/android:build_java",
-    "//chrome/browser/feedback/android:factory_java",
-    "//chrome/browser/feedback/android:java",
-    "//chrome/browser/notifications:java",
-    "//chrome/browser/password_manager/android:java_resources",
-    "//chrome/browser/password_manager/android:utils_java",
-    "//chrome/browser/password_manager/android/bottom_sheet:java",
-    "//chrome/browser/profiles/android:java",
-    "//components/browser_ui/bottomsheet/android:java",
-    "//components/browser_ui/notifications/android:java",
-    "//third_party/androidx:androidx_annotation_annotation_java",
-    "//third_party/jni_zero:jni_zero_java",
-    "//ui/android:ui_java",
-  ]
-}
-
-android_library("settings_dialog_java") {
-  resources_package = "org.chromium.chrome.browser.access_loss"
-
-  sources = [
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinator.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsMediator.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsProperties.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsViewBinder.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogController.java",
-  ]
-
-  deps = [
-    ":enums_java",
-    ":helper_java",
-    ":settings_dialog_java_resources",
-    ":utils_java",
-    "//base:base_java",
-    "//build/android:build_java",
-    "//chrome/browser/feedback/android:java",
-    "//chrome/browser/feedback/android:java_resources",
-    "//chrome/browser/password_manager/android:java_resources",
-    "//chrome/browser/password_manager/android:utils_java",
-    "//components/browser_ui/settings/android:java",
-    "//third_party/androidx:androidx_annotation_annotation_java",
-    "//third_party/androidx:androidx_browser_browser_java",
-    "//ui/android:ui_java",
-  ]
-}
-
-android_resources("settings_dialog_java_resources") {
-  sources = [ "java/res/layout/access_loss_dialog_settings_view.xml" ]
-
-  deps = [ "//components/browser_ui/styles/android:java_resources" ]
-}
-
-robolectric_library("junit") {
-  testonly = true
-  resources_package = "org.chromium.chrome.browser.access_loss"
-
-  sources = [
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinatorTest.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogControllerTest.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelperTest.java",
-    "java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinatorTest.java",
-  ]
-
-  deps = [
-    ":enums_java",
-    ":helper_java",
-    ":settings_dialog_java",
-    ":settings_dialog_java_resources",
-    ":utils_java",
-    "//base:base_java",
-    "//base:base_java_test_support",
-    "//base:base_junit_test_support",
-    "//chrome/android:chrome_jni_headers_java",
-    "//chrome/browser/feedback/android:java",
-    "//chrome/browser/feedback/android:java_resources",
-    "//chrome/browser/flags:java",
-    "//chrome/browser/notifications:java",
-    "//chrome/browser/password_manager/android:utils_java",
-    "//chrome/browser/password_manager/android/bottom_sheet:java",
-    "//chrome/browser/profiles/android:java",
-    "//chrome/browser/ui/android/strings:ui_strings_grd",
-    "//components/browser_ui/bottomsheet/android:java",
-    "//components/browser_ui/notifications/android:java",
-    "//components/browser_ui/notifications/android:utils_java",
-    "//components/browser_ui/settings/android:java",
-    "//components/browser_ui/theme/android:java_resources",
-    "//third_party/androidx:androidx_annotation_annotation_java",
-    "//third_party/androidx:androidx_browser_browser_java",
-    "//third_party/androidx:androidx_test_core_java",
-    "//third_party/junit",
-    "//third_party/mockito:mockito_java",
-    "//ui/android:ui_java",
-    "//ui/android:ui_java_test_support",
-  ]
-}
-
-source_set("public") {
-  sources = [
-    "password_access_loss_warning_bridge.h",
-    "password_access_loss_warning_bridge_impl.cc",
-    "password_access_loss_warning_bridge_impl.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chrome/android:chrome_jni_headers",
-    "//chrome/browser/password_manager/android:utils",
-    "//chrome/browser/profiles:profile",
-    "//components/password_manager/core/browser:metrics_util",
-    "//components/password_manager/core/browser/features:password_features",
-    "//components/prefs:prefs",
-    "//ui/android:android",
-    "//ui/gfx:native_widget_types",
-  ]
-}
-
-android_library("javatests") {
-  testonly = true
-  resources_package = "org.chromium.chrome.browser.access_loss"
-
-  sources = [ "java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java" ]
-
-  deps = [
-    ":enums_java",
-    ":helper_java",
-    "//base:base_java",
-    "//base:base_java_test_support",
-    "//chrome/android:chrome_java",
-    "//chrome/browser/flags:java",
-    "//chrome/browser/password_manager/android:utils_java",
-    "//chrome/browser/password_manager/android/bottom_sheet:java_resources",
-    "//chrome/browser/profiles/android:java",
-    "//chrome/browser/ui/android/night_mode:night_mode_java_test_support",
-    "//chrome/test/android:chrome_java_integration_test_support",
-    "//chrome/test/android:chrome_java_transit",
-    "//chrome/test/android:chrome_java_unit_test_support",
-    "//components/browser_ui/bottomsheet/android:java",
-    "//components/browser_ui/bottomsheet/android:manager_java",
-    "//components/browser_ui/bottomsheet/android/test:java",
-    "//third_party/androidx:androidx_test_espresso_espresso_core_java",
-    "//third_party/androidx:androidx_test_runner_java",
-    "//third_party/junit:junit",
-    "//third_party/mockito:mockito_java",
-    "//ui/android:ui_java_test_support",
-    "//ui/android:ui_no_recycler_view_java",
-  ]
-}
-
-source_set("test_support") {
-  testonly = true
-
-  deps = [
-    ":public",
-    "//components/prefs:prefs",
-    "//testing/gmock",
-    "//ui/gfx:native_widget_types",
-  ]
-
-  sources = [
-    "mock_password_access_loss_warning_bridge.cc",
-    "mock_password_access_loss_warning_bridge.h",
-  ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [ "password_access_loss_warning_bridge_impl_unittest.cc" ]
-  deps = [
-    ":public",
-    "//base/test:test_support",
-    "//chrome/browser/password_manager/android:unit_tests",
-    "//components/password_manager/core/browser",
-    "//components/password_manager/core/browser/features:password_features",
-    "//components/password_manager/core/common:common",
-    "//components/prefs:prefs",
-    "//components/prefs:test_support",
-    "//content/test:test_support",
-  ]
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/res/layout/access_loss_dialog_settings_view.xml b/chrome/browser/password_manager/android/access_loss/java/res/layout/access_loss_dialog_settings_view.xml
deleted file mode 100644
index 2dd9b6cd..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/res/layout/access_loss_dialog_settings_view.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2024 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<ScrollView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center">
-  <LinearLayout
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical">
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-
-      <TextView
-          android:id="@+id/title"
-          android:layout_width="0dp"
-          android:layout_height="wrap_content"
-          android:layout_weight="1"
-          android:layout_marginStart="@dimen/password_manager_dialog_text_margin"
-          android:layout_marginEnd="@dimen/password_manager_dialog_text_margin"
-          android:paddingTop="@dimen/password_manager_dialog_title_padding_top"
-          android:textAppearance="@style/TextAppearance.Headline.Primary" />
-
-      <org.chromium.ui.widget.ChromeImageButton
-          android:id="@+id/help_button"
-          android:layout_height="48dp"
-          android:layout_width="48dp"
-          android:layout_weight="0"
-          android:layout_marginTop="4dp"
-          android:layout_marginEnd="4dp"
-          android:background="?attr/selectableItemBackground"
-          app:srcCompat ="@drawable/ic_help_and_feedback"
-          android:contentDescription="@string/help"
-          android:visibility="gone"/>
-    </LinearLayout>
-
-    <org.chromium.ui.widget.TextViewWithLeading
-        android:id="@+id/details"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/password_manager_dialog_text_margin"
-        android:layout_marginEnd="@dimen/password_manager_dialog_text_margin"
-        android:layout_marginTop="@dimen/password_manager_dialog_details_padding_top"
-        android:textAppearance="@style/TextAppearance.TextMedium.Secondary"
-        app:leading="@dimen/text_size_medium_leading" />
-  </LinearLayout>
-</ScrollView>
\ No newline at end of file
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/AccessLossWarningMetricsRecorder.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/AccessLossWarningMetricsRecorder.java
deleted file mode 100644
index 541e1ed..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/AccessLossWarningMetricsRecorder.java
+++ /dev/null
@@ -1,165 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.VisibleForTesting;
-
-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;
-
-/** Used by the access loss warning UI to log metrics. */
-@NullMarked
-public class AccessLossWarningMetricsRecorder {
-
-    // These values are persisted to logs. Entries should not be renumbered and
-    // numeric values should never be reused.
-    @IntDef({
-        PasswordAccessLossWarningUserAction.MAIN_ACTION,
-        PasswordAccessLossWarningUserAction.HELP_CENTER,
-        PasswordAccessLossWarningUserAction.DISMISS,
-        PasswordAccessLossWarningUserAction.COUNT
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface PasswordAccessLossWarningUserAction {
-        int MAIN_ACTION = 0;
-        int HELP_CENTER = 1;
-        int DISMISS = 2;
-        int COUNT = 3;
-    }
-
-    // These values are persisted to logs. Entries should not be renumbered and
-    // numeric values should never be reused.
-    @IntDef({
-        PasswordAccessLossWarningExportStep.PWD_SERIALIZATION_FAILED,
-        PasswordAccessLossWarningExportStep.EXPORT_CANCELED,
-        PasswordAccessLossWarningExportStep.NO_SCREEN_LOCK_SET_UP,
-        PasswordAccessLossWarningExportStep.SAVE_PWD_FILE_FAILED,
-        PasswordAccessLossWarningExportStep.AUTHENTICATION_EXPIRED,
-        PasswordAccessLossWarningExportStep.EXPORT_DONE,
-        PasswordAccessLossWarningExportStep.IMPORT_CANCELED,
-        PasswordAccessLossWarningExportStep.PASSWORD_IMPORT,
-        PasswordAccessLossWarningExportStep.COUNT
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface PasswordAccessLossWarningExportStep {
-        int PWD_SERIALIZATION_FAILED = 0;
-        int EXPORT_CANCELED = 1;
-        int NO_SCREEN_LOCK_SET_UP = 2;
-        int SAVE_PWD_FILE_FAILED = 3;
-        // Authentication can expire while Chrome app was in the background with an ongoing export
-        // flow. In this case the export flow is aborted when Chrome app is foregrounded.
-        int AUTHENTICATION_EXPIRED = 4;
-        // This step ends the flow with no GMS Core.
-        int EXPORT_DONE = 5;
-        int IMPORT_CANCELED = 6;
-        // This step ends the flow with new GMS Core and migration failed.
-        int PASSWORD_IMPORT = 7;
-        int COUNT = 8;
-    }
-
-    static final String PASSWORD_ACCESS_LOSS_WARNING_USER_ACTION_PREFIX =
-            "PasswordManager.PasswordAccessLossWarningSheet.";
-    static final String PASSWORD_ACCESS_LOSS_WARNING_USER_ACTION_SUFFIX = ".UserAction";
-
-    static final String ACCESS_LOSS_DIALOG_METRIC_PREFIX =
-            "PasswordManager.PasswordAccessLossWarningDialog";
-    static final String ACCESS_LOSS_DIALOG_SHOWN_SUFFIX = ".Shown";
-    static final String ACCESS_LOSS_DIALOG_ACTION_SUFFIX = ".UserAction";
-    static final String EXPORT_FLOW_METRIC_TITLE =
-            "PasswordManager.PasswordAccessLossWarningExportFlow.";
-
-    static final String EXPORT_FLOW_FINAL_STEP_SUFFIX = ".FinalStep";
-
-    static void logAccessLossWarningSheetUserAction(
-            @PasswordAccessLossWarningType int warningType,
-            @PasswordAccessLossWarningUserAction int action) {
-        RecordHistogram.recordEnumeratedHistogram(
-                getUserActionHistogramName(warningType),
-                action,
-                PasswordAccessLossWarningUserAction.COUNT);
-    }
-
-    private AccessLossWarningMetricsRecorder() {}
-
-    @VisibleForTesting
-    static String getUserActionHistogramName(@PasswordAccessLossWarningType int warningType) {
-        // The name of the histogram will have the format:
-        // PasswordManager.PasswordAccessLossWarningSheet.{AccessLossWarningType}.UserAction
-        return PASSWORD_ACCESS_LOSS_WARNING_USER_ACTION_PREFIX
-                + getAccessLossWarningTypeName(warningType)
-                + PASSWORD_ACCESS_LOSS_WARNING_USER_ACTION_SUFFIX;
-    }
-
-    static void logDialogShownMetric(@PasswordAccessLossWarningType int warningType) {
-        RecordHistogram.recordEnumeratedHistogram(
-                getDialogShownHistogramName(),
-                warningType,
-                PasswordAccessLossWarningType.MAX_VALUE);
-    }
-
-    static void logDialogUserActionMetric(
-            @PasswordAccessLossWarningType int warningType,
-            @PasswordAccessLossWarningUserAction int action) {
-        RecordHistogram.recordEnumeratedHistogram(
-                getDialogUserActionHistogramName(warningType),
-                action,
-                PasswordAccessLossWarningUserAction.COUNT);
-    }
-
-    public static void logExportFlowLastStepMetric(
-            @PasswordAccessLossWarningType int warningType,
-            @PasswordAccessLossWarningExportStep int exportStep) {
-        RecordHistogram.recordEnumeratedHistogram(
-                getExportFlowFinalStepHistogramName(warningType),
-                exportStep,
-                PasswordAccessLossWarningExportStep.COUNT);
-    }
-
-    @VisibleForTesting
-    static String getDialogShownHistogramName() {
-        // The name of the histogram will be PasswordManager.PasswordAccessLossWarningDialog.Shown
-        return ACCESS_LOSS_DIALOG_METRIC_PREFIX + ACCESS_LOSS_DIALOG_SHOWN_SUFFIX;
-    }
-
-    @VisibleForTesting
-    static String getDialogUserActionHistogramName(@PasswordAccessLossWarningType int warningType) {
-        // The name of the histogram will will have the format:
-        // PasswordManager.PasswordAccessLossWarningDialog.{AccessLossWarningType}.UserAction
-        return ACCESS_LOSS_DIALOG_METRIC_PREFIX
-                + getAccessLossWarningTypeName(warningType)
-                + ACCESS_LOSS_DIALOG_ACTION_SUFFIX;
-    }
-
-    @VisibleForTesting
-    public static String getExportFlowFinalStepHistogramName(
-            @PasswordAccessLossWarningType int warningType) {
-        // The name of the histogram will have the format:
-        // PasswordManager.PasswordAccessLossWarningExportFlow.{AccessLossWarningType}.FinalStep
-        return EXPORT_FLOW_METRIC_TITLE
-                + getAccessLossWarningTypeName(warningType)
-                + EXPORT_FLOW_FINAL_STEP_SUFFIX;
-    }
-
-    private static @Nullable String getAccessLossWarningTypeName(
-            @PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return "NoGmsCore";
-            case PasswordAccessLossWarningType.NO_UPM:
-                return "NoUPM";
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return "OnlyAccountUpm";
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return "NewGmsCoreMigrationFailed";
-        }
-        assert false : "Unhandled warning type: " + warningType;
-        return null;
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinator.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinator.java
deleted file mode 100644
index 0077eb5..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinator.java
+++ /dev/null
@@ -1,199 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.build.NullUtil.assertNonNull;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.logDialogShownMetric;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.DETAILS;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.HELP_BUTTON_CALLBACK;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.HELP_BUTTON_VISIBILITY;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.TITLE;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import org.chromium.base.Callback;
-import org.chromium.base.ContextUtils;
-import org.chromium.build.annotations.Initializer;
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.components.browser_ui.settings.SettingsCustomTabLauncher;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-
-/**
- * Shows the warning to the user explaining why they are not able to access Google Password Manager.
- * This warning is displayed when user tries to access Google Password Manager in 3 cases: 1) They
- * don't have GMS Core installed. 2) They have an outdated GMS Core. 3) The local passwords
- * migration to GMS Core failed. The user is then proposed to either update GMS Core (if it's a
- * valid option) or to run the passwords export flow.
- */
-@NullMarked
-public class PasswordAccessLossDialogSettingsCoordinator {
-    private Context mContext;
-    private ModalDialogManager mModalDialogManager;
-    private PasswordAccessLossDialogSettingsMediator mMediator;
-
-    @Initializer
-    public void showPasswordAccessLossDialog(
-            Context context,
-            ModalDialogManager modalDialogManager,
-            @PasswordAccessLossWarningType int warningType,
-            Callback<Context> launchGmsUpdate,
-            Runnable launchExportFlow,
-            SettingsCustomTabLauncher settingsCustomTabLauncher) {
-        assert warningType != PasswordAccessLossWarningType.NONE
-                : "Only show the access loss dialog if there is a reason to warn about.";
-        mContext = context;
-        mModalDialogManager = modalDialogManager;
-        mMediator =
-                new PasswordAccessLossDialogSettingsMediator(
-                        assertNonNull(ContextUtils.activityFromContext(context)),
-                        modalDialogManager,
-                        warningType,
-                        launchGmsUpdate,
-                        launchExportFlow,
-                        settingsCustomTabLauncher);
-        View dialogCustomView = createAndBindDialogCustomView(warningType);
-        mModalDialogManager.showDialog(
-                createDialogModel(context, warningType, dialogCustomView),
-                ModalDialogManager.ModalDialogType.APP);
-        logDialogShownMetric(warningType);
-    }
-
-    private View createAndBindDialogCustomView(@PasswordAccessLossWarningType int warningType) {
-        View dialogCustomView =
-                LayoutInflater.from(mContext)
-                        .inflate(R.layout.access_loss_dialog_settings_view, null);
-        Resources resources = mContext.getResources();
-        PropertyModel model =
-                new PropertyModel.Builder(PasswordAccessLossDialogSettingsProperties.ALL_KEYS)
-                        .with(TITLE, resources.getString(getTitle(warningType)))
-                        .with(DETAILS, resources.getString(getDescription(warningType)))
-                        .with(HELP_BUTTON_VISIBILITY, getHelpButtonVisible(warningType))
-                        .with(HELP_BUTTON_CALLBACK, mMediator::onHelpButtonClicked)
-                        .build();
-        PropertyModelChangeProcessor.create(
-                model, dialogCustomView, PasswordAccessLossDialogSettingsViewBinder::bind);
-        return dialogCustomView;
-    }
-
-    private PropertyModel createDialogModel(
-            Context context, @PasswordAccessLossWarningType int warningType, View customView) {
-        Resources resources = context.getResources();
-        return new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
-                .with(ModalDialogProperties.CONTROLLER, mMediator)
-                .with(ModalDialogProperties.CUSTOM_VIEW, customView)
-                .with(
-                        ModalDialogProperties.POSITIVE_BUTTON_TEXT,
-                        resources,
-                        getPositiveButtonText(warningType))
-                .with(
-                        ModalDialogProperties.NEGATIVE_BUTTON_TEXT,
-                        resources,
-                        getNegativeButtonText(warningType))
-                .with(
-                        ModalDialogProperties.BUTTON_STYLES,
-                        ModalDialogProperties.ButtonStyles.PRIMARY_FILLED_NEGATIVE_OUTLINE)
-                .build();
-    }
-
-    private int getTitle(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return R.string.access_loss_no_gms_title;
-            case PasswordAccessLossWarningType.NO_UPM:
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return R.string.access_loss_update_gms_title;
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return R.string.access_loss_fix_problem_title;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning";
-                return 0;
-        }
-        assert false : "Value of PasswordAccessLossWarningType is not known";
-        return 0;
-    }
-
-    private int getDescription(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return R.string.access_loss_no_gms_desc;
-            case PasswordAccessLossWarningType.NO_UPM:
-                return R.string.access_loss_no_upm_desc;
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return R.string.access_loss_update_gms_desc;
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return R.string.access_loss_fix_problem_desc;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning";
-                return 0;
-        }
-        assert false : "Value of PasswordAccessLossWarningType is not known";
-        return 0;
-    }
-
-    private int getPositiveButtonText(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return R.string.access_loss_no_gms_positive_button_text;
-            case PasswordAccessLossWarningType.NO_UPM:
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return R.string.password_manager_outdated_gms_positive_button;
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return R.string.access_loss_fix_problem_positive_button_text;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning";
-                return 0;
-        }
-        assert false : "Value of PasswordAccessLossWarningType is not known";
-        return 0;
-    }
-
-    private int getNegativeButtonText(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return R.string.close;
-            case PasswordAccessLossWarningType.NO_UPM:
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return R.string.password_manager_outdated_gms_negative_button;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning";
-                return 0;
-        }
-        assert false : "Value of PasswordAccessLossWarningType is not known";
-        return 0;
-    }
-
-    private boolean getHelpButtonVisible(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-            case PasswordAccessLossWarningType.NO_UPM:
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return true;
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return false;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning";
-                return false;
-        }
-        assert false : "Value of PasswordAccessLossWarningType is not known";
-        return false;
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinatorTest.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinatorTest.java
deleted file mode 100644
index 5d847fe..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsCoordinatorTest.java
+++ /dev/null
@@ -1,258 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.DISMISS;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.HELP_CENTER;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.MAIN_ACTION;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.getDialogShownHistogramName;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.getDialogUserActionHistogramName;
-import static org.chromium.chrome.browser.password_manager.HelpUrlLauncher.GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL;
-import static org.chromium.chrome.browser.password_manager.HelpUrlLauncher.KEEP_APPS_AND_DEVICES_WORKING_WITH_GMS_CORE_SUPPORT_URL;
-
-import android.app.Activity;
-import android.content.Context;
-import android.view.View;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.Robolectric;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.Callback;
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.HistogramWatcher;
-import org.chromium.components.browser_ui.settings.SettingsCustomTabLauncher;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.test.util.modaldialog.FakeModalDialogManager;
-import org.chromium.ui.widget.ChromeImageButton;
-
-/** Tests for {@link PasswordAccessLossDialogSettingsCoordinator} */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-@Batch(Batch.PER_CLASS)
-public class PasswordAccessLossDialogSettingsCoordinatorTest {
-
-    private final PasswordAccessLossDialogSettingsCoordinator mCoordinator =
-            new PasswordAccessLossDialogSettingsCoordinator();
-    private final FakeModalDialogManager mModalDialogManager =
-            new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
-    private Activity mActivity;
-
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    @Mock private Callback<Context> mLaunchGmsCoreUpdate;
-    @Mock private Runnable mLaunchExportFlow;
-
-    @Mock private SettingsCustomTabLauncher mSettingsCustomTabLauncher;
-
-    @Before
-    public void setUp() {
-        mActivity = Robolectric.buildActivity(Activity.class).create().start().resume().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
-    }
-
-    @Test
-    public void showsAndHidesAccessLossDialog() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogShownHistogramName(),
-                                PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED)
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType
-                                                .NEW_GMS_CORE_MIGRATION_FAILED),
-                                DISMISS)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        Assert.assertNotNull(mDialogModel);
-
-        mModalDialogManager.clickNegativeButton();
-        Assert.assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void launchesGmsCoreUpdateWhenNoUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_UPM),
-                                MAIN_ACTION)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.NO_UPM,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        Assert.assertNotNull(mDialogModel);
-
-        mModalDialogManager.clickPositiveButton();
-        verify(mLaunchGmsCoreUpdate).onResult(any());
-        Assert.assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void launchesGmsCoreUpdateWhenOnlyAccountUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM),
-                                MAIN_ACTION)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        Assert.assertNotNull(mDialogModel);
-
-        mModalDialogManager.clickPositiveButton();
-        verify(mLaunchGmsCoreUpdate).onResult(any());
-        Assert.assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void launchesExportFlowWhenNoGmsCore() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_GMS_CORE),
-                                MAIN_ACTION)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.NO_GMS_CORE,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        Assert.assertNotNull(mDialogModel);
-
-        mModalDialogManager.clickPositiveButton();
-        verify(mLaunchExportFlow).run();
-        Assert.assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void launchesExportFlowWhenMigrationFailed() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType
-                                                .NEW_GMS_CORE_MIGRATION_FAILED),
-                                MAIN_ACTION)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        Assert.assertNotNull(mDialogModel);
-
-        mModalDialogManager.clickPositiveButton();
-        verify(mLaunchExportFlow).run();
-        Assert.assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void opensGmsCoreHelpWhenHelpButtonClicked() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_UPM),
-                                HELP_CENTER)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.NO_UPM,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        findHelpButton().performClick();
-        verify(mSettingsCustomTabLauncher)
-                .openUrlInCct(
-                        eq(mActivity), eq(KEEP_APPS_AND_DEVICES_WORKING_WITH_GMS_CORE_SUPPORT_URL));
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void opensGmsCoreSupportedDevicesHelpWhenHelpButtonClicked() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getDialogUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_GMS_CORE),
-                                HELP_CENTER)
-                        .build();
-
-        mCoordinator.showPasswordAccessLossDialog(
-                mActivity,
-                mModalDialogManager,
-                PasswordAccessLossWarningType.NO_GMS_CORE,
-                mLaunchGmsCoreUpdate,
-                mLaunchExportFlow,
-                mSettingsCustomTabLauncher);
-        findHelpButton().performClick();
-        verify(mSettingsCustomTabLauncher)
-                .openUrlInCct(eq(mActivity), eq(GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL));
-
-        histogram.assertExpected();
-    }
-
-    private ChromeImageButton findHelpButton() {
-        final PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        final View customView = mDialogModel.get(ModalDialogProperties.CUSTOM_VIEW);
-        Assert.assertNotNull(customView);
-        return customView.findViewById(R.id.help_button);
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsMediator.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsMediator.java
deleted file mode 100644
index c7b1cba..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsMediator.java
+++ /dev/null
@@ -1,115 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.logDialogUserActionMetric;
-
-import android.app.Activity;
-import android.content.Context;
-
-import org.chromium.base.Callback;
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction;
-import org.chromium.chrome.browser.password_manager.HelpUrlLauncher;
-import org.chromium.components.browser_ui.settings.SettingsCustomTabLauncher;
-import org.chromium.ui.modaldialog.DialogDismissalCause;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonType;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Mediator for the password access loss dialog meant to be shown in Chrome settings. It handles
- * interactions with the UI.
- */
-@NullMarked
-class PasswordAccessLossDialogSettingsMediator implements ModalDialogProperties.Controller {
-    private final Activity mActivity;
-    private final ModalDialogManager mModalDialogManager;
-    private final @PasswordAccessLossWarningType int mWarningType;
-    private final Callback<Context> mLaunchGmsUpdate;
-    private final Runnable mLaunchExportFlow;
-    private final SettingsCustomTabLauncher mSettingsCustomTabLauncher;
-
-    public PasswordAccessLossDialogSettingsMediator(
-            Activity activity,
-            ModalDialogManager modalDialogManager,
-            @PasswordAccessLossWarningType int warningType,
-            Callback<Context> launchGmsUpdate,
-            Runnable launchExportFlow,
-            SettingsCustomTabLauncher settingsCustomTabLauncher) {
-        mActivity = activity;
-        mModalDialogManager = modalDialogManager;
-        mWarningType = warningType;
-        mLaunchGmsUpdate = launchGmsUpdate;
-        mLaunchExportFlow = launchExportFlow;
-        mSettingsCustomTabLauncher = settingsCustomTabLauncher;
-    }
-
-    private void runPositiveButtonCallback() {
-        switch (mWarningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                mLaunchExportFlow.run();
-                break;
-            case PasswordAccessLossWarningType.NO_UPM:
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                mLaunchGmsUpdate.onResult(mActivity.getApplicationContext());
-                break;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning";
-                break;
-        }
-    }
-
-    void onHelpButtonClicked() {
-        logDialogUserActionMetric(mWarningType, PasswordAccessLossWarningUserAction.HELP_CENTER);
-        switch (mWarningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                mSettingsCustomTabLauncher.openUrlInCct(
-                        mActivity, HelpUrlLauncher.GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL);
-                return;
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                assert false
-                        : "The help button shouldn't be displayed for"
-                                + " `NEW_GMS_CORE_MIGRATION_FAILED`.";
-                return;
-            case PasswordAccessLossWarningType.NO_UPM:
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                mSettingsCustomTabLauncher.openUrlInCct(
-                        mActivity,
-                        HelpUrlLauncher.KEEP_APPS_AND_DEVICES_WORKING_WITH_GMS_CORE_SUPPORT_URL);
-                return;
-            case PasswordAccessLossWarningType.NONE:
-                assert false
-                        : "Illegal value `PasswordAccessLossWarningType.NONE` when trying to show"
-                                + " password access loss warning.";
-                return;
-        }
-
-        assert false : "Value " + mWarningType + " of PasswordAccessLossWarningType is not known";
-    }
-
-    @Override
-    public void onClick(PropertyModel model, int buttonType) {
-        if (buttonType == ButtonType.POSITIVE) {
-            logDialogUserActionMetric(
-                    mWarningType, PasswordAccessLossWarningUserAction.MAIN_ACTION);
-            runPositiveButtonCallback();
-        } else if (buttonType == ButtonType.NEGATIVE) {
-            logDialogUserActionMetric(mWarningType, PasswordAccessLossWarningUserAction.DISMISS);
-        }
-        mModalDialogManager.dismissDialog(
-                model,
-                buttonType == ButtonType.POSITIVE
-                        ? DialogDismissalCause.POSITIVE_BUTTON_CLICKED
-                        : DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
-    }
-
-    @Override
-    public void onDismiss(PropertyModel model, int dismissalCause) {}
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsProperties.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsProperties.java
deleted file mode 100644
index 977b4e84..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsProperties.java
+++ /dev/null
@@ -1,29 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModel.ReadableBooleanPropertyKey;
-import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
-
-@NullMarked
-class PasswordAccessLossDialogSettingsProperties {
-    private PasswordAccessLossDialogSettingsProperties() {}
-
-    static final PropertyModel.ReadableObjectPropertyKey<String> TITLE =
-            new ReadableObjectPropertyKey<>("dialog title");
-    static final PropertyModel.ReadableObjectPropertyKey<String> DETAILS =
-            new ReadableObjectPropertyKey<>("dialog details");
-    static final PropertyModel.ReadableBooleanPropertyKey HELP_BUTTON_VISIBILITY =
-            new ReadableBooleanPropertyKey("is help button visible");
-    static final PropertyModel.ReadableObjectPropertyKey<Runnable> HELP_BUTTON_CALLBACK =
-            new ReadableObjectPropertyKey<>("help button callback");
-
-    static final PropertyKey[] ALL_KEYS = {
-        TITLE, DETAILS, HELP_BUTTON_VISIBILITY, HELP_BUTTON_CALLBACK
-    };
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsViewBinder.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsViewBinder.java
deleted file mode 100644
index f1ef6a3..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossDialogSettingsViewBinder.java
+++ /dev/null
@@ -1,42 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.DETAILS;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.HELP_BUTTON_CALLBACK;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.HELP_BUTTON_VISIBILITY;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.TITLE;
-
-import android.view.View;
-import android.widget.TextView;
-
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Maps {@link PasswordAccessLossDialogSettingsProperties} changes in a {@link PropertyModel} to
- * {@link PasswordAccessLossDialogSettingsCoordinator}'s modal dialog custom view.
- */
-@NullMarked
-class PasswordAccessLossDialogSettingsViewBinder {
-    private PasswordAccessLossDialogSettingsViewBinder() {}
-
-    static void bind(PropertyModel model, View view, PropertyKey propertyKey) {
-        if (propertyKey == TITLE) {
-            ((TextView) view.findViewById(R.id.title)).setText(model.get(TITLE));
-        } else if (propertyKey == DETAILS) {
-            ((TextView) view.findViewById(R.id.details)).setText(model.get(DETAILS));
-        } else if (propertyKey == HELP_BUTTON_VISIBILITY) {
-            boolean isVisible = model.get(HELP_BUTTON_VISIBILITY);
-            view.findViewById(R.id.help_button).setVisibility(isVisible ? View.VISIBLE : View.GONE);
-        } else if (propertyKey == HELP_BUTTON_CALLBACK) {
-            view.findViewById(R.id.help_button)
-                    .setOnClickListener(button -> model.get(HELP_BUTTON_CALLBACK).run());
-        } else {
-            assert false : "Property " + propertyKey.toString() + " not handled in the binder";
-        }
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossNotificationProperties.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossNotificationProperties.java
deleted file mode 100644
index dbee9d72..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossNotificationProperties.java
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.access_loss;
-
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/** Properties defined here reflect the visible state of the password access loss notification. */
-@NullMarked
-class PasswordAccessLossNotificationProperties {
-    public static final PropertyModel.WritableObjectPropertyKey<String> TITLE =
-            new PropertyModel.WritableObjectPropertyKey<>("sheet_title");
-    public static final PropertyModel.WritableObjectPropertyKey<String> TEXT =
-            new PropertyModel.WritableObjectPropertyKey<>("sheet_text");
-
-    public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {TITLE, TEXT};
-
-    private PasswordAccessLossNotificationProperties() {}
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogController.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogController.java
deleted file mode 100644
index c0b6a49e..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogController.java
+++ /dev/null
@@ -1,110 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.DETAILS;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.HELP_BUTTON_CALLBACK;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.HELP_BUTTON_VISIBILITY;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossDialogSettingsProperties.TITLE;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.chrome.browser.password_manager.HelpUrlLauncher;
-import org.chromium.components.browser_ui.settings.SettingsCustomTabLauncher;
-import org.chromium.ui.modaldialog.DialogDismissalCause;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonType;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-
-/**
- * Shows the warning to the user explaining why they are not able to access Google Password Manager.
- * This warning is displayed for the users who don't have GMS Core installed and don't have
- * passwords in the profile store (either they never had them or passwords were removed after export
- * flow).
- */
-@NullMarked
-public class PasswordAccessLossPostExportDialogController
-        implements ModalDialogProperties.Controller {
-    private final Context mContext;
-    private final ModalDialogManager mModalDialogManager;
-    private final SettingsCustomTabLauncher mSettingsCustomTabLauncher;
-
-    public PasswordAccessLossPostExportDialogController(
-            Context context,
-            ModalDialogManager modalDialogManager,
-            SettingsCustomTabLauncher settingsCustomTabLauncher) {
-        mContext = context;
-        mModalDialogManager = modalDialogManager;
-        mSettingsCustomTabLauncher = settingsCustomTabLauncher;
-    }
-
-    public void showPostExportDialog() {
-        View dialogCustomView = createAndBindDialogCustomView();
-        mModalDialogManager.showDialog(
-                createDialogModel(dialogCustomView), ModalDialogManager.ModalDialogType.APP);
-    }
-
-    private View createAndBindDialogCustomView() {
-        View dialogCustomView =
-                LayoutInflater.from(mContext)
-                        .inflate(R.layout.access_loss_dialog_settings_view, null);
-        Resources resources = mContext.getResources();
-        PropertyModel model =
-                new PropertyModel.Builder(PasswordAccessLossDialogSettingsProperties.ALL_KEYS)
-                        .with(
-                                TITLE,
-                                resources.getString(R.string.access_loss_no_gms_no_passwords_title))
-                        .with(
-                                DETAILS,
-                                resources.getString(R.string.access_loss_no_gms_no_passwords_desc))
-                        .with(HELP_BUTTON_VISIBILITY, true)
-                        .with(
-                                HELP_BUTTON_CALLBACK,
-                                () -> {
-                                    Activity activity = ContextUtils.activityFromContext(mContext);
-                                    if (activity == null) return;
-                                    mSettingsCustomTabLauncher.openUrlInCct(
-                                            activity,
-                                            HelpUrlLauncher
-                                                    .GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL);
-                                })
-                        .build();
-        PropertyModelChangeProcessor.create(
-                model, dialogCustomView, PasswordAccessLossDialogSettingsViewBinder::bind);
-        return dialogCustomView;
-    }
-
-    private PropertyModel createDialogModel(View customView) {
-        Resources resources = mContext.getResources();
-        return new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
-                .with(ModalDialogProperties.CONTROLLER, this)
-                .with(ModalDialogProperties.CUSTOM_VIEW, customView)
-                .with(ModalDialogProperties.NEGATIVE_BUTTON_TEXT, resources, R.string.close)
-                .with(
-                        ModalDialogProperties.BUTTON_STYLES,
-                        ModalDialogProperties.ButtonStyles.PRIMARY_FILLED_NEGATIVE_OUTLINE)
-                .build();
-    }
-
-    @Override
-    public void onClick(PropertyModel model, int buttonType) {
-        mModalDialogManager.dismissDialog(
-                model,
-                buttonType == ButtonType.POSITIVE
-                        ? DialogDismissalCause.POSITIVE_BUTTON_CLICKED
-                        : DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
-    }
-
-    @Override
-    public void onDismiss(PropertyModel model, int dismissalCause) {}
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogControllerTest.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogControllerTest.java
deleted file mode 100644
index 170d027..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossPostExportDialogControllerTest.java
+++ /dev/null
@@ -1,84 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-
-import android.app.Activity;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.Robolectric;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.browser.password_manager.HelpUrlLauncher;
-import org.chromium.components.browser_ui.settings.SettingsCustomTabLauncher;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.test.util.modaldialog.FakeModalDialogManager;
-import org.chromium.ui.widget.ChromeImageButton;
-
-/** Tests for {@link PasswordAccessLossPostExportDialogController} */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class PasswordAccessLossPostExportDialogControllerTest {
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    private Activity mActivity;
-    private FakeModalDialogManager mModalDialogManager;
-
-    @Mock private SettingsCustomTabLauncher mSettingsCustomTabLauncher;
-    PasswordAccessLossPostExportDialogController mController;
-
-    @Before
-    public void setUp() {
-        mActivity = Robolectric.buildActivity(Activity.class).create().start().resume().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
-        mModalDialogManager = new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
-    }
-
-    @Test
-    public void testDialogDismissed() {
-        mController =
-                new PasswordAccessLossPostExportDialogController(
-                        mActivity, mModalDialogManager, mSettingsCustomTabLauncher);
-        mController.showPostExportDialog();
-        assertNotNull(mModalDialogManager.getShownDialogModel());
-
-        mModalDialogManager.clickNegativeButton();
-        assertNull(mModalDialogManager.getShownDialogModel());
-    }
-
-    @Test
-    public void testOpensGmsCoreSupportedDevicesHelpArticle() {
-        mController =
-                new PasswordAccessLossPostExportDialogController(
-                        mActivity, mModalDialogManager, mSettingsCustomTabLauncher);
-        mController.showPostExportDialog();
-
-        getHelpButton().performClick();
-        verify(mSettingsCustomTabLauncher)
-                .openUrlInCct(
-                        eq(mActivity),
-                        eq(HelpUrlLauncher.GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL));
-    }
-
-    private ChromeImageButton getHelpButton() {
-        final PropertyModel mDialogModel = mModalDialogManager.getShownDialogModel();
-        final View customView = mDialogModel.get(ModalDialogProperties.CUSTOM_VIEW);
-        assertNotNull(customView);
-        return customView.findViewById(R.id.help_button);
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelper.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelper.java
deleted file mode 100644
index 05064197..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelper.java
+++ /dev/null
@@ -1,214 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.DISMISS;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.HELP_CENTER;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.MAIN_ACTION;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.logAccessLossWarningSheetUserAction;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.ALL_KEYS;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.BUTTON_ACTION;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.BUTTON_TITLE;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.SHEET_TEXT;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.SHEET_TITLE;
-import static org.chromium.chrome.browser.password_manager.HelpUrlLauncher.GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL;
-import static org.chromium.chrome.browser.password_manager.HelpUrlLauncher.KEEP_APPS_AND_DEVICES_WORKING_WITH_GMS_CORE_SUPPORT_URL;
-
-import android.app.Activity;
-import android.text.SpannableString;
-import android.view.View;
-
-import org.chromium.base.Callback;
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.build.annotations.Nullable;
-import org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetCoordinator;
-import org.chromium.chrome.browser.password_manager.CustomTabIntentHelper;
-import org.chromium.chrome.browser.password_manager.GmsUpdateLauncher;
-import org.chromium.chrome.browser.password_manager.HelpUrlLauncher;
-import org.chromium.chrome.browser.password_manager.PasswordExportLauncher;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
-import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.text.ChromeClickableSpan;
-import org.chromium.ui.text.SpanApplier;
-
-/** Entry-point to the access loss warning UI surface. */
-@NullMarked
-public class PasswordAccessLossWarningHelper {
-    final Activity mActivity;
-    final BottomSheetController mBottomSheetController;
-    final Profile mProfile;
-    final HelpUrlLauncher mHelpUrlLauncher;
-
-    public static final String PASSWORD_ACCESS_LOSS_WARNING_USER_ACTION_PREFIX =
-            "PasswordManager.PasswordAccessLossWarningSheet.";
-    public static final String PASSWORD_ACCESS_LOSS_WARNING_USER_ACTION_SUFFIX = ".UserAction";
-
-    public PasswordAccessLossWarningHelper(
-            Activity activity,
-            BottomSheetController bottomSheetController,
-            Profile profile,
-            CustomTabIntentHelper customTabIntentHelper) {
-        mBottomSheetController = bottomSheetController;
-        mProfile = profile;
-        mActivity = activity;
-        mHelpUrlLauncher = new HelpUrlLauncher(customTabIntentHelper);
-    }
-
-    public void show(@PasswordAccessLossWarningType int warningType) {
-        mBottomSheetController.addObserver(
-                createBottomSheetObserver(mBottomSheetController, warningType));
-        SimpleNoticeSheetCoordinator coordinator =
-                new SimpleNoticeSheetCoordinator(mActivity, mBottomSheetController);
-        PropertyModel model = getModelForWarningType(warningType);
-        if (model == null) {
-            return;
-        }
-        coordinator.showSheet(model);
-    }
-
-    /** Creates the model that has the text and functionality appropriate for the warning type. */
-    @Nullable PropertyModel getModelForWarningType(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return buildAccessLossWarningNoGms();
-            case PasswordAccessLossWarningType.NO_UPM:
-                // Fallthrough, same as ONLY_ACCOUNT_UPM.
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return buildAccessLossWarningAboutGmsUpdate(warningType);
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return buildAccessLossWarningAboutManualMigration();
-        }
-        assert false : "Unhandled warning type: " + warningType;
-        return null;
-    }
-
-    /** GMS Core doesn't exist on the device so the user is asked to export their passwords. */
-    PropertyModel buildAccessLossWarningNoGms() {
-        return new PropertyModel.Builder(ALL_KEYS)
-                .with(
-                        SHEET_TITLE,
-                        mActivity.getString(R.string.pwd_access_loss_warning_no_gms_core_title))
-                .with(
-                        SHEET_TEXT,
-                        getBottomSheetTextWithLink(
-                                mActivity.getString(
-                                        R.string.pwd_access_loss_warning_no_gms_core_text),
-                                (unusedView) -> {
-                                    mHelpUrlLauncher.showHelpArticle(
-                                            mActivity, GOOGLE_PLAY_SUPPORTED_DEVICES_SUPPORT_URL);
-                                    logAccessLossWarningSheetUserAction(
-                                            PasswordAccessLossWarningType.NO_GMS_CORE, HELP_CENTER);
-                                }))
-                .with(
-                        BUTTON_TITLE,
-                        mActivity.getString(
-                                R.string.pwd_access_loss_warning_no_gms_core_button_text))
-                .with(
-                        BUTTON_ACTION,
-                        () -> {
-                            PasswordExportLauncher.showMainSettingsAndStartExport(mActivity);
-                            logAccessLossWarningSheetUserAction(
-                                    PasswordAccessLossWarningType.NO_GMS_CORE, MAIN_ACTION);
-                        })
-                .build();
-    }
-
-    /**
-     * GMS Core on the device doesn't support UPM so the user is asked to update GMS Core.
-     *
-     * @param warningType that is used to track user action metrics.
-     * @return the property model for the warning sheet.
-     */
-    PropertyModel buildAccessLossWarningAboutGmsUpdate(
-            @PasswordAccessLossWarningType int warningType) {
-        return new PropertyModel.Builder(ALL_KEYS)
-                .with(
-                        SHEET_TITLE,
-                        mActivity.getString(R.string.pwd_access_loss_warning_update_gms_core_title))
-                .with(
-                        SHEET_TEXT,
-                        getBottomSheetTextWithLink(
-                                mActivity.getString(
-                                        warningType == PasswordAccessLossWarningType.NO_UPM
-                                                ? R.string.pwd_access_loss_warning_no_upm_text
-                                                : R.string
-                                                        .pwd_access_loss_warning_update_gms_core_text),
-                                (unusedView) -> {
-                                    mHelpUrlLauncher.showHelpArticle(
-                                            mActivity,
-                                            KEEP_APPS_AND_DEVICES_WORKING_WITH_GMS_CORE_SUPPORT_URL);
-                                    logAccessLossWarningSheetUserAction(warningType, HELP_CENTER);
-                                }))
-                .with(
-                        BUTTON_TITLE,
-                        mActivity.getString(
-                                R.string.pwd_access_loss_warning_update_gms_core_button_text))
-                .with(
-                        BUTTON_ACTION,
-                        () -> {
-                            GmsUpdateLauncher.launch(mActivity);
-                            logAccessLossWarningSheetUserAction(warningType, MAIN_ACTION);
-                        })
-                .build();
-    }
-
-    /**
-     * GMS Core version on the device is new enough for UPM, but the automatic migration failed, so
-     * the user is asked to manually do the migration by performing export and import.
-     */
-    PropertyModel buildAccessLossWarningAboutManualMigration() {
-        return new PropertyModel.Builder(ALL_KEYS)
-                .with(
-                        SHEET_TITLE,
-                        mActivity.getString(
-                                R.string.pwd_access_loss_warning_manual_migration_title))
-                .with(
-                        SHEET_TEXT,
-                        SpannableString.valueOf(
-                                mActivity.getString(
-                                        R.string.pwd_access_loss_warning_manual_migration_text)))
-                .with(
-                        BUTTON_TITLE,
-                        mActivity.getString(
-                                R.string.pwd_access_loss_warning_manual_migration_button_text))
-                .with(
-                        BUTTON_ACTION,
-                        () -> {
-                            PasswordExportLauncher.showMainSettingsAndStartExport(mActivity);
-                            logAccessLossWarningSheetUserAction(
-                                    PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED,
-                                    MAIN_ACTION);
-                        })
-                .build();
-    }
-
-    private SpannableString getBottomSheetTextWithLink(String sheetText, Callback<View> callback) {
-        return SpanApplier.applySpans(
-                sheetText,
-                new SpanApplier.SpanInfo(
-                        "<link>", "</link>", new ChromeClickableSpan(mActivity, callback)));
-    }
-
-    private BottomSheetObserver createBottomSheetObserver(
-            BottomSheetController bottomSheetController,
-            @PasswordAccessLossWarningType int warningType) {
-        return new EmptyBottomSheetObserver() {
-            @Override
-            public void onSheetClosed(@StateChangeReason int reason) {
-                if (reason == StateChangeReason.SWIPE
-                        || reason == StateChangeReason.BACK_PRESS
-                        || reason == StateChangeReason.TAP_SCRIM
-                        || reason == StateChangeReason.OMNIBOX_FOCUS) {
-                    logAccessLossWarningSheetUserAction(warningType, DISMISS);
-                }
-                bottomSheetController.removeObserver(this);
-            }
-        };
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelperTest.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelperTest.java
deleted file mode 100644
index 71fcedb..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningHelperTest.java
+++ /dev/null
@@ -1,393 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.DISMISS;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.HELP_CENTER;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningUserAction.MAIN_ACTION;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.getUserActionHistogramName;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.BUTTON_ACTION;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.BUTTON_TITLE;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.SHEET_TEXT;
-import static org.chromium.chrome.browser.bottom_sheet.SimpleNoticeSheetProperties.SHEET_TITLE;
-import static org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason.BACK_PRESS;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.text.SpannableString;
-import android.view.View;
-
-import androidx.annotation.StringRes;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-import org.robolectric.Robolectric;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.HistogramWatcher;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.password_manager.CustomTabIntentHelper;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.text.ChromeClickableSpan;
-import org.chromium.ui.text.SpanApplier;
-
-import java.util.List;
-
-/** Tests for {@link PasswordAccessLossWarningHelper} */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-@Batch(Batch.PER_CLASS)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PasswordAccessLossWarningHelperTest {
-    private PasswordAccessLossWarningHelper mHelper;
-    private final ArgumentCaptor<BottomSheetObserver> mBottomSheetObserverCaptor =
-            ArgumentCaptor.forClass(BottomSheetObserver.class);
-    private Activity mActivity;
-
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
-    @Mock private BottomSheetController mBottomSheetController;
-    @Mock private Profile mProfile;
-
-    @Before
-    public void setUp() {
-        mActivity = Robolectric.buildActivity(Activity.class).create().start().resume().get();
-        mActivity.setTheme(R.style.Theme_BrowserUI_DayNight);
-        CustomTabIntentHelper customTabIntentHelper = (Context context, Intent intent) -> intent;
-        mHelper =
-                new PasswordAccessLossWarningHelper(
-                        mActivity, mBottomSheetController, mProfile, customTabIntentHelper);
-    }
-
-    private void setUpBottomSheetController() {
-        when(mBottomSheetController.requestShowContent(any(), anyBoolean())).thenReturn(true);
-        doNothing().when(mBottomSheetController).addObserver(mBottomSheetObserverCaptor.capture());
-    }
-
-    private String getStringWithoutLink(@StringRes int stringId) {
-        String sheetText = mActivity.getString(stringId);
-        return SpanApplier.applySpans(
-                        sheetText,
-                        new SpanApplier.SpanInfo(
-                                "<link>",
-                                "</link>",
-                                new ChromeClickableSpan(mActivity, view -> {})))
-                .toString();
-    }
-
-    private void clickSpan(SpannableString spannableString) {
-        ChromeClickableSpan[] spans =
-                spannableString.getSpans(0, spannableString.length(), ChromeClickableSpan.class);
-        spans[0].onClick(new View(mActivity.getBaseContext()));
-    }
-
-    private void notifyBottomSheetObservers(
-            List<BottomSheetObserver> observers, @StateChangeReason int reason) {
-        assertNotNull(observers);
-
-        for (BottomSheetObserver observer : observers) {
-            observer.onSheetClosed(reason);
-        }
-    }
-
-    @Test
-    public void showsSheet() {
-        setUpBottomSheetController();
-        mHelper.show(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED);
-        verify(mBottomSheetController).requestShowContent(any(), anyBoolean());
-        verify(mBottomSheetController, times(2)).addObserver(any());
-    }
-
-    @Test
-    public void getsModelForNoGmsCore() {
-        PropertyModel model =
-                mHelper.getModelForWarningType(PasswordAccessLossWarningType.NO_GMS_CORE);
-        assertEquals(
-                model.get(SHEET_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_no_gms_core_title));
-        assertEquals(
-                model.get(SHEET_TEXT).toString(),
-                getStringWithoutLink(R.string.pwd_access_loss_warning_no_gms_core_text));
-        assertEquals(
-                model.get(BUTTON_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_no_gms_core_button_text));
-    }
-
-    @Test
-    public void getsModelForNoUpm() {
-        PropertyModel model = mHelper.getModelForWarningType(PasswordAccessLossWarningType.NO_UPM);
-        assertEquals(
-                model.get(SHEET_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_update_gms_core_title));
-        assertEquals(
-                model.get(SHEET_TEXT).toString(),
-                getStringWithoutLink(R.string.pwd_access_loss_warning_no_upm_text));
-        assertEquals(
-                model.get(BUTTON_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_update_gms_core_button_text));
-    }
-
-    @Test
-    public void getsModelForOnlyAccountUpm() {
-        PropertyModel model =
-                mHelper.getModelForWarningType(PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM);
-        assertEquals(
-                model.get(SHEET_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_update_gms_core_title));
-        assertEquals(
-                model.get(SHEET_TEXT).toString(),
-                getStringWithoutLink(R.string.pwd_access_loss_warning_update_gms_core_text));
-        assertEquals(
-                model.get(BUTTON_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_update_gms_core_button_text));
-    }
-
-    @Test
-    public void getsModelForFailedMigration() {
-        PropertyModel model =
-                mHelper.getModelForWarningType(
-                        PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED);
-        assertEquals(
-                model.get(SHEET_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_manual_migration_title));
-        assertEquals(
-                model.get(SHEET_TEXT).toString(),
-                mActivity
-                        .getString(R.string.pwd_access_loss_warning_manual_migration_text)
-                        .toString());
-        assertEquals(
-                model.get(BUTTON_TITLE),
-                mActivity.getString(R.string.pwd_access_loss_warning_manual_migration_button_text));
-    }
-
-    @Test
-    public void mainActionForNoGmsCore() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_GMS_CORE),
-                                MAIN_ACTION)
-                        .build();
-
-        PropertyModel model =
-                mHelper.getModelForWarningType(PasswordAccessLossWarningType.NO_GMS_CORE);
-        model.get(BUTTON_ACTION).run();
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void mainActionForNoUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(PasswordAccessLossWarningType.NO_UPM),
-                                MAIN_ACTION)
-                        .build();
-
-        PropertyModel model = mHelper.getModelForWarningType(PasswordAccessLossWarningType.NO_UPM);
-        model.get(BUTTON_ACTION).run();
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void mainActionForOnlyAccountUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM),
-                                MAIN_ACTION)
-                        .build();
-
-        PropertyModel model =
-                mHelper.getModelForWarningType(PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM);
-        model.get(BUTTON_ACTION).run();
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void mainActionForFailedMigration() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType
-                                                .NEW_GMS_CORE_MIGRATION_FAILED),
-                                MAIN_ACTION)
-                        .build();
-
-        PropertyModel model =
-                mHelper.getModelForWarningType(
-                        PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED);
-        model.get(BUTTON_ACTION).run();
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void inProductHelpForNoGmsCore() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_GMS_CORE),
-                                HELP_CENTER)
-                        .build();
-
-        PropertyModel model =
-                mHelper.getModelForWarningType(PasswordAccessLossWarningType.NO_GMS_CORE);
-        SpannableString text = model.get(SHEET_TEXT);
-        clickSpan(text);
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void inProductHelpForNoUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(PasswordAccessLossWarningType.NO_UPM),
-                                HELP_CENTER)
-                        .build();
-
-        PropertyModel model = mHelper.getModelForWarningType(PasswordAccessLossWarningType.NO_UPM);
-        SpannableString text = model.get(SHEET_TEXT);
-        clickSpan(text);
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void inProductHelpForOnlyAccountUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM),
-                                HELP_CENTER)
-                        .build();
-
-        PropertyModel model =
-                mHelper.getModelForWarningType(PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM);
-        SpannableString text = model.get(SHEET_TEXT);
-        clickSpan(text);
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void sheetDismissalForFailedMigration() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType
-                                                .NEW_GMS_CORE_MIGRATION_FAILED),
-                                DISMISS)
-                        .build();
-
-        mHelper.show(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED);
-        ArgumentCaptor<BottomSheetObserver> observerCaptor =
-                ArgumentCaptor.forClass(BottomSheetObserver.class);
-        verify(mBottomSheetController, times(2)).addObserver(observerCaptor.capture());
-        verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true));
-
-        notifyBottomSheetObservers(observerCaptor.getAllValues(), BACK_PRESS);
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void sheetDismissalForNoGmsCore() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType.NO_GMS_CORE),
-                                DISMISS)
-                        .build();
-
-        mHelper.show(PasswordAccessLossWarningType.NO_GMS_CORE);
-        ArgumentCaptor<BottomSheetObserver> observerCaptor =
-                ArgumentCaptor.forClass(BottomSheetObserver.class);
-        verify(mBottomSheetController, times(2)).addObserver(observerCaptor.capture());
-        verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true));
-
-        notifyBottomSheetObservers(observerCaptor.getAllValues(), BACK_PRESS);
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void sheetDismissalForNoUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(PasswordAccessLossWarningType.NO_UPM),
-                                DISMISS)
-                        .build();
-
-        mHelper.show(PasswordAccessLossWarningType.NO_UPM);
-        ArgumentCaptor<BottomSheetObserver> observerCaptor =
-                ArgumentCaptor.forClass(BottomSheetObserver.class);
-        verify(mBottomSheetController, times(2)).addObserver(observerCaptor.capture());
-        verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true));
-
-        notifyBottomSheetObservers(observerCaptor.getAllValues(), BACK_PRESS);
-
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void sheetDismissalForOnlyAccountUpm() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getUserActionHistogramName(
-                                        PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM),
-                                DISMISS)
-                        .build();
-
-        mHelper.show(PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM);
-        ArgumentCaptor<BottomSheetObserver> observerCaptor =
-                ArgumentCaptor.forClass(BottomSheetObserver.class);
-        verify(mBottomSheetController, times(2)).addObserver(observerCaptor.capture());
-        verify(mBottomSheetController).requestShowContent(any(BottomSheetContent.class), eq(true));
-
-        notifyBottomSheetObservers(observerCaptor.getAllValues(), BACK_PRESS);
-
-        histogram.assertExpected();
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java
deleted file mode 100644
index e0d7dfb3..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PasswordAccessLossWarningRenderTest.java
+++ /dev/null
@@ -1,139 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking;
-import static org.chromium.base.test.util.ApplicationTestUtils.finishActivity;
-import static org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed;
-import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
-
-import android.view.View;
-
-import androidx.test.filters.MediumTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-
-import org.chromium.base.test.params.ParameterAnnotations;
-import org.chromium.base.test.params.ParameterSet;
-import org.chromium.base.test.params.ParameterizedRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
-import org.chromium.chrome.browser.password_manager.CustomTabIntentHelper;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.test.transit.ChromeTransitTestRules;
-import org.chromium.chrome.test.transit.FreshCtaTransitTestRule;
-import org.chromium.chrome.test.transit.page.WebPageStation;
-import org.chromium.chrome.test.util.ChromeRenderTestRule;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport;
-import org.chromium.ui.base.WindowAndroid;
-import org.chromium.ui.test.util.RenderTestRule.Component;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * These tests render screenshots of touch to fill for credit cards sheet and compare them to a gold
- * standard.
- */
-@RunWith(ParameterizedRunner.class)
-@Batch(Batch.PER_CLASS)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PasswordAccessLossWarningRenderTest {
-
-    @ParameterAnnotations.ClassParameter
-    private static final List<ParameterSet> sClassParams =
-            Arrays.asList(
-                    new ParameterSet().value(false, false).name("Default"),
-                    new ParameterSet().value(false, true).name("RTL"),
-                    new ParameterSet().value(true, false).name("NightMode"));
-
-    public FreshCtaTransitTestRule mActivityTestRule =
-            ChromeTransitTestRules.freshChromeTabbedActivityRule();
-
-    @Rule
-    public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
-
-    @Rule
-    public final ChromeRenderTestRule mRenderTestRule =
-            ChromeRenderTestRule.Builder.withPublicCorpus()
-                    .setRevision(3)
-                    .setBugComponent(Component.UI_BROWSER_PASSWORDS)
-                    .build();
-
-    @Mock private Profile mProfile;
-    @Mock private CustomTabIntentHelper mCustomTabIntentHelper;
-
-    private BottomSheetController mBottomSheetController;
-    private PasswordAccessLossWarningHelper mHelper;
-    private WebPageStation mPage;
-
-    public PasswordAccessLossWarningRenderTest(boolean nightModeEnabled, boolean useRtlLayout) {
-        setRtlForTesting(useRtlLayout);
-        ChromeNightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled);
-        mRenderTestRule.setNightModeEnabled(nightModeEnabled);
-        mRenderTestRule.setVariantPrefix(useRtlLayout ? "RTL" : "LTR");
-    }
-
-    @Before
-    public void setUp() throws InterruptedException {
-        mPage = mActivityTestRule.startOnBlankPage();
-        mActivityTestRule.waitForActivityCompletelyLoaded();
-        mBottomSheetController =
-                mActivityTestRule
-                        .getActivity()
-                        .getRootUiCoordinatorForTesting()
-                        .getBottomSheetController();
-        runOnUiThreadBlocking(
-                () -> {
-                    WindowAndroid windowAndroid =
-                            mActivityTestRule.getActivity().getWindowAndroid();
-                    mHelper =
-                            new PasswordAccessLossWarningHelper(
-                                    mActivityTestRule.getActivity(),
-                                    BottomSheetControllerProvider.from(windowAndroid),
-                                    mProfile,
-                                    mCustomTabIntentHelper);
-                });
-    }
-
-    @After
-    public void tearDown() {
-        setRtlForTesting(false);
-        try {
-            finishActivity(mActivityTestRule.getActivity());
-        } catch (Exception e) {
-            // Activity was already closed (e.g. due to last test tearing down the suite).
-        }
-        runOnUiThreadBlocking(() -> tearDownNightModeAfterChromeActivityDestroyed());
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"RenderTest"})
-    public void testShowsAccessLossWarningSheetWithNoGmsCore() throws IOException {
-        runOnUiThreadBlocking(
-                () -> {
-                    mHelper.show(PasswordAccessLossWarningType.NO_GMS_CORE);
-                });
-        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
-
-        View bottomSheetView = mActivityTestRule.getActivity().findViewById(R.id.bottom_sheet);
-        mRenderTestRule.render(bottomSheetView, "access_loss_warning_sheet");
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinator.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinator.java
deleted file mode 100644
index 3e755dfb..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinator.java
+++ /dev/null
@@ -1,152 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.chromium.build.NullUtil.assumeNonNull;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossNotificationProperties.ALL_KEYS;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossNotificationProperties.TEXT;
-import static org.chromium.chrome.browser.access_loss.PasswordAccessLossNotificationProperties.TITLE;
-
-import android.content.Context;
-
-import androidx.annotation.VisibleForTesting;
-
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.chrome.browser.notifications.NotificationConstants;
-import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
-import org.chromium.chrome.browser.notifications.NotificationWrapperBuilderFactory;
-import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions.ChannelId;
-import org.chromium.components.browser_ui.notifications.BaseNotificationManagerProxyFactory;
-import org.chromium.components.browser_ui.notifications.NotificationMetadata;
-import org.chromium.components.browser_ui.notifications.NotificationWrapper;
-import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Shows the password access loss notification with the properties belonging to the current {@link
- * PasswordAccessLossWarningType}.
- */
-@NullMarked
-public class PwdAccessLossNotificationCoordinator {
-    @VisibleForTesting protected static final String TAG = "access_loss_warning";
-
-    private final Context mContext;
-
-    public PwdAccessLossNotificationCoordinator(Context context) {
-        mContext = context;
-    }
-
-    private static NotificationWrapperBuilder createNotificationBuilder() {
-        return NotificationWrapperBuilderFactory.createNotificationWrapperBuilder(
-                ChannelId.BROWSER,
-                new NotificationMetadata(
-                        NotificationUmaTracker.SystemNotificationType.UPM_ACCESS_LOSS_WARNING,
-                        TAG,
-                        NotificationConstants.NOTIFICATION_ID_UPM_ACCESS_LOSS));
-    }
-
-    /**
-     * Shows the password access loss notification for the given {@link
-     * PasswordAccessLossWarningType}.
-     *
-     * @param warningType determines the looks of the notification.
-     */
-    public void showNotification(@PasswordAccessLossWarningType int warningType) {
-        PropertyModel model = getModelForNotificationType(warningType);
-        String title = model.get(TITLE);
-        String contents = model.get(TEXT).toString();
-
-        // TODO: crbug.com/354886479 - Add the notification actions.
-        NotificationWrapperBuilder notificationWrapperBuilder =
-                createNotificationBuilder()
-                        .setSmallIcon(R.drawable.ic_chrome)
-                        .setShowWhen(false)
-                        .setAutoCancel(true)
-                        .setLocalOnly(true)
-                        .setContentTitle(title)
-                        .setContentText(contents)
-                        .setTicker(contents);
-
-        NotificationWrapper notification =
-                notificationWrapperBuilder.buildWithBigTextStyle(contents);
-
-        BaseNotificationManagerProxyFactory.create().notify(notification);
-
-        NotificationUmaTracker.getInstance()
-                .onNotificationShown(
-                        NotificationUmaTracker.SystemNotificationType.UPM_ACCESS_LOSS_WARNING,
-                        notification.getNotification());
-    }
-
-    /**
-     * Creates the model that has the text and functionality appropriate for the notification type.
-     *
-     * @param warningType determines the values in the models.
-     * @return the model for the notification.
-     */
-    PropertyModel getModelForNotificationType(@PasswordAccessLossWarningType int warningType) {
-        switch (warningType) {
-            case PasswordAccessLossWarningType.NO_GMS_CORE:
-                return buildAccessLossNotificationNoGms();
-            case PasswordAccessLossWarningType.NO_UPM:
-                // Fallthrough, same as ONLY_ACCOUNT_UPM.
-            case PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM:
-                return buildAccessLossNotificationAboutGmsUpdate();
-            case PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED:
-                return buildAccessLossNotificationAboutManualMigration();
-            default:
-                assert false : "Unhandled warning type. " + warningType;
-                return assumeNonNull(null);
-        }
-    }
-
-    /**
-     * GMS Core doesn't exist on the device so the user is asked to export their passwords.
-     *
-     * @return the model for the notification.
-     */
-    PropertyModel buildAccessLossNotificationNoGms() {
-        return new PropertyModel.Builder(ALL_KEYS)
-                .with(TITLE, mContext.getString(R.string.pwd_access_loss_warning_no_gms_core_title))
-                .with(
-                        TEXT,
-                        mContext.getString(R.string.pwd_access_loss_notification_no_gms_core_text))
-                .build();
-    }
-
-    /**
-     * GMS Core on the device doesn't support UPM so the user is asked to update GMS Core.
-     *
-     * @return the model for the notification.
-     */
-    PropertyModel buildAccessLossNotificationAboutGmsUpdate() {
-        return new PropertyModel.Builder(ALL_KEYS)
-                .with(
-                        TITLE,
-                        mContext.getString(R.string.pwd_access_loss_warning_update_gms_core_title))
-                .with(
-                        TEXT,
-                        mContext.getString(
-                                R.string.pwd_access_loss_notification_update_gms_core_text))
-                .build();
-    }
-
-    /**
-     * GMS Core version on the device is new enough for UPM, but the automatic migration failed, so
-     * the user is asked to manually do the migration by performing export and import.
-     *
-     * @return the model for the notification.
-     */
-    PropertyModel buildAccessLossNotificationAboutManualMigration() {
-        return new PropertyModel.Builder(ALL_KEYS)
-                .with(
-                        TITLE,
-                        mContext.getString(R.string.pwd_access_loss_warning_manual_migration_title))
-                .with(
-                        TEXT,
-                        mContext.getString(R.string.pwd_access_loss_warning_manual_migration_text))
-                .build();
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinatorTest.java b/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinatorTest.java
deleted file mode 100644
index 0f14ea0b..0000000
--- a/chrome/browser/password_manager/android/access_loss/java/src/org/chromium/chrome/browser/access_loss/PwdAccessLossNotificationCoordinatorTest.java
+++ /dev/null
@@ -1,149 +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.
-
-package org.chromium.chrome.browser.access_loss;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.Mockito.verify;
-
-import android.app.Notification;
-import android.content.Context;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowNotification;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Features.EnableFeatures;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.notifications.NotificationUmaTracker.SystemNotificationType;
-import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions;
-import org.chromium.components.browser_ui.notifications.BaseNotificationManagerProxy;
-import org.chromium.components.browser_ui.notifications.BaseNotificationManagerProxyFactory;
-import org.chromium.components.browser_ui.notifications.NotificationFeatureMap;
-import org.chromium.components.browser_ui.notifications.NotificationMetadata;
-import org.chromium.components.browser_ui.notifications.NotificationWrapper;
-
-/** Tests for {@link PwdAccessLossNotificationCoordinator} */
-@RunWith(BaseRobolectricTestRunner.class)
-@EnableFeatures({NotificationFeatureMap.CACHE_NOTIIFICATIONS_ENABLED})
-@Config(manifest = Config.NONE)
-@Batch(Batch.PER_CLASS)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PwdAccessLossNotificationCoordinatorTest {
-    private PwdAccessLossNotificationCoordinator mCoordinator;
-    private Context mContext;
-
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
-    @Mock private BaseNotificationManagerProxy mNotificationManagerProxy;
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.getApplication();
-        BaseNotificationManagerProxyFactory.setInstanceForTesting(mNotificationManagerProxy);
-        mCoordinator = new PwdAccessLossNotificationCoordinator(mContext);
-    }
-
-    @Test
-    public void testShowNotification() {
-        ArgumentCaptor<NotificationWrapper> captor =
-                ArgumentCaptor.forClass(NotificationWrapper.class);
-        mCoordinator.showNotification(PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM);
-        verify(mNotificationManagerProxy).notify(captor.capture());
-
-        NotificationWrapper notificationWrapper = captor.getValue();
-        Notification notification = notificationWrapper.getNotification();
-        assertEquals(R.drawable.ic_chrome, notification.getSmallIcon().getResId());
-        assertEquals(ChromeChannelDefinitions.ChannelId.BROWSER, notification.getChannelId());
-
-        NotificationMetadata notificationMetadata = notificationWrapper.getMetadata();
-        assertEquals(SystemNotificationType.UPM_ACCESS_LOSS_WARNING, notificationMetadata.type);
-        assertEquals(PwdAccessLossNotificationCoordinator.TAG, notificationMetadata.tag);
-    }
-
-    @Test
-    public void testShowNotificationForNoGmsCore() {
-        ArgumentCaptor<NotificationWrapper> captor =
-                ArgumentCaptor.forClass(NotificationWrapper.class);
-        mCoordinator.showNotification(PasswordAccessLossWarningType.NO_GMS_CORE);
-        verify(mNotificationManagerProxy).notify(captor.capture());
-
-        ShadowNotification shadowNotification =
-                Shadows.shadowOf(captor.getValue().getNotification());
-        assertFalse(shadowNotification.isWhenShown());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_warning_no_gms_core_title),
-                shadowNotification.getContentTitle());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_notification_no_gms_core_text),
-                shadowNotification.getContentText());
-    }
-
-    @Test
-    public void testShowNotificationForNoUpm() {
-        ArgumentCaptor<NotificationWrapper> captor =
-                ArgumentCaptor.forClass(NotificationWrapper.class);
-        mCoordinator.showNotification(PasswordAccessLossWarningType.NO_UPM);
-        verify(mNotificationManagerProxy).notify(captor.capture());
-
-        ShadowNotification shadowNotification =
-                Shadows.shadowOf(captor.getValue().getNotification());
-        assertFalse(shadowNotification.isWhenShown());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_warning_update_gms_core_title),
-                shadowNotification.getContentTitle());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_notification_update_gms_core_text),
-                shadowNotification.getContentText());
-    }
-
-    @Test
-    public void testShowNotificationForOnlyAccountUpm() {
-        ArgumentCaptor<NotificationWrapper> captor =
-                ArgumentCaptor.forClass(NotificationWrapper.class);
-        mCoordinator.showNotification(PasswordAccessLossWarningType.ONLY_ACCOUNT_UPM);
-        verify(mNotificationManagerProxy).notify(captor.capture());
-
-        ShadowNotification shadowNotification =
-                Shadows.shadowOf(captor.getValue().getNotification());
-        assertFalse(shadowNotification.isWhenShown());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_warning_update_gms_core_title),
-                shadowNotification.getContentTitle());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_notification_update_gms_core_text),
-                shadowNotification.getContentText());
-    }
-
-    @Test
-    public void testShowNotificationWhenMigrationFailed() {
-        ArgumentCaptor<NotificationWrapper> captor =
-                ArgumentCaptor.forClass(NotificationWrapper.class);
-        mCoordinator.showNotification(PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED);
-        verify(mNotificationManagerProxy).notify(captor.capture());
-
-        ShadowNotification shadowNotification =
-                Shadows.shadowOf(captor.getValue().getNotification());
-        assertFalse(shadowNotification.isWhenShown());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_warning_manual_migration_title),
-                shadowNotification.getContentTitle());
-        assertEquals(
-                mContext.getString(R.string.pwd_access_loss_warning_manual_migration_text),
-                shadowNotification.getContentText());
-    }
-}
diff --git a/chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.cc b/chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.cc
deleted file mode 100644
index e626070..0000000
--- a/chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.cc
+++ /dev/null
@@ -1,10 +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/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h"
-
-MockPasswordAccessLossWarningBridge::MockPasswordAccessLossWarningBridge() =
-    default;
-MockPasswordAccessLossWarningBridge::~MockPasswordAccessLossWarningBridge() =
-    default;
diff --git a/chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h b/chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h
deleted file mode 100644
index cf09258..0000000
--- a/chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_MOCK_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_MOCK_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_H_
-
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-class MockPasswordAccessLossWarningBridge
-    : public PasswordAccessLossWarningBridge {
- public:
-  MockPasswordAccessLossWarningBridge();
-  MockPasswordAccessLossWarningBridge(
-      const MockPasswordAccessLossWarningBridge&) = delete;
-  MockPasswordAccessLossWarningBridge& operator=(
-      const MockPasswordAccessLossWarningBridge&) = delete;
-  ~MockPasswordAccessLossWarningBridge() override;
-
-  MOCK_METHOD(bool,
-              ShouldShowAccessLossNoticeSheet,
-              (PrefService*, bool),
-              (override));
-  MOCK_METHOD(
-      void,
-      MaybeShowAccessLossNoticeSheet,
-      (PrefService*,
-       const gfx::NativeWindow,
-       Profile*,
-       bool,
-       password_manager_android_util::PasswordAccessLossWarningTriggers),
-      (override));
-};
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_MOCK_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_H_
diff --git a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h b/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h
deleted file mode 100644
index 559ec916..0000000
--- a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_H_
-
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/prefs/pref_service.h"
-#include "ui/gfx/native_widget_types.h"
-
-// This bridge is responsible for triggering all the variants of the access loss
-// warning sheet from the cpp side.
-class PasswordAccessLossWarningBridge {
- public:
-  virtual ~PasswordAccessLossWarningBridge() = default;
-
-  // Determines if any of the access loss warning sheets should be shown.
-  virtual bool ShouldShowAccessLossNoticeSheet(PrefService* pref_service,
-                                               bool called_at_startup) = 0;
-  // Tries to call the Java code that will show an access loss warning sheet.
-  // Showing the sheet can fail if there is no BottomSheetController or the
-  // BottomSheetcontroller suppresses the sheet. Content is suppressed if higher
-  // priority content is in the sheet, the sheet is expanded beyond the peeking
-  // state, or the browser is in a mode that does not support showing the sheet.
-  virtual void MaybeShowAccessLossNoticeSheet(
-      PrefService* pref_service,
-      const gfx::NativeWindow window,
-      Profile* profile,
-      bool called_at_startup,
-      password_manager_android_util::PasswordAccessLossWarningTriggers
-          trigger_source) = 0;
-};
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_H_
diff --git a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.cc b/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.cc
deleted file mode 100644
index 5af2990..0000000
--- a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.cc
+++ /dev/null
@@ -1,123 +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/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
-
-#include "base/android/build_info.h"
-#include "base/android/jni_android.h"
-#include "base/feature_list.h"
-#include "chrome/android/chrome_jni_headers/PasswordAccessLossWarningBridge_jni.h"
-#include "chrome/browser/password_manager/android/password_manager_util_bridge.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "ui/android/window_android.h"
-
-constexpr base::TimeDelta kMinIntervalBetweenWarnings = base::Days(1);
-constexpr base::TimeDelta kMinIntervalBetweenWarningsAtStartup = base::Days(7);
-
-PasswordAccessLossWarningBridgeImpl::PasswordAccessLossWarningBridgeImpl() =
-    default;
-
-PasswordAccessLossWarningBridgeImpl::~PasswordAccessLossWarningBridgeImpl() =
-    default;
-
-bool PasswordAccessLossWarningBridgeImpl::ShouldShowAccessLossNoticeSheet(
-    PrefService* pref_service,
-    bool called_at_startup) {
-  // The warning should not be shown on builds without UPM.
-  if (!GetUtilBridge().IsInternalBackendPresent()) {
-    return false;
-  }
-
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid)) {
-    // If the login DB is being deprecated, the warning is no longer relevant.
-    return false;
-  }
-
-  // The trigger point of showing the sheet on startup has to combine the
-  // warning type check with checking the number of passwords in the store. This
-  // can only be done async and should only be done if the other conditions in
-  // this function are met.
-  if (password_manager_android_util::GetPasswordAccessLossWarningType(
-          pref_service) ==
-      password_manager_android_util::PasswordAccessLossWarningType::kNone) {
-    return false;
-  }
-
-  base::Time last_shown_timestamp = pref_service->GetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp);
-  base::TimeDelta time_since_last_shown =
-      base::Time::Now() - last_shown_timestamp;
-  if (time_since_last_shown < kMinIntervalBetweenWarnings) {
-    return false;
-  }
-
-  base::Time last_shown_timestamp_at_startup = pref_service->GetTime(
-      password_manager::prefs::
-          kPasswordAccessLossWarningShownAtStartupTimestamp);
-  base::TimeDelta time_since_last_shown_at_startup =
-      base::Time::Now() - last_shown_timestamp_at_startup;
-  if (called_at_startup &&
-      time_since_last_shown_at_startup < kMinIntervalBetweenWarningsAtStartup) {
-    return false;
-  }
-
-  return true;
-}
-
-void PasswordAccessLossWarningBridgeImpl::MaybeShowAccessLossNoticeSheet(
-    PrefService* pref_service,
-    const gfx::NativeWindow window,
-    Profile* profile,
-    bool called_at_startup,
-    password_manager_android_util::PasswordAccessLossWarningTriggers
-        trigger_source) {
-  if (profile == nullptr) {
-    return;
-  }
-  if (!window) {
-    return;
-  }
-  JNIEnv* env = base::android::AttachCurrentThread();
-  jni_zero::ScopedJavaLocalRef<jobject> java_bridge =
-      Java_PasswordAccessLossWarningBridge_create(env, window->GetJavaObject(),
-                                                  profile->GetJavaObject());
-  if (!java_bridge) {
-    return;
-  }
-
-  password_manager_android_util::PasswordAccessLossWarningType warning_type =
-      password_manager_android_util::GetPasswordAccessLossWarningType(
-          pref_service);
-  Java_PasswordAccessLossWarningBridge_show(env, java_bridge,
-                                            static_cast<int>(warning_type));
-  password_manager_android_util::RecordPasswordAccessLossWarningTriggerSource(
-      trigger_source, warning_type);
-
-  pref_service->SetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-      base::Time::Now());
-  if (called_at_startup) {
-    pref_service->SetTime(password_manager::prefs::
-                              kPasswordAccessLossWarningShownAtStartupTimestamp,
-                          base::Time::Now());
-  }
-}
-
-void PasswordAccessLossWarningBridgeImpl::SetUtilBridgeForTesting(
-    std::unique_ptr<
-        password_manager_android_util::PasswordManagerUtilBridgeInterface>
-        util_bridge) {
-  CHECK(!util_bridge_);
-  util_bridge_ = std::move(util_bridge);
-}
-
-password_manager_android_util::PasswordManagerUtilBridgeInterface&
-PasswordAccessLossWarningBridgeImpl::GetUtilBridge() {
-  if (!util_bridge_) {
-    util_bridge_ = std::make_unique<
-        password_manager_android_util::PasswordManagerUtilBridge>();
-  }
-  return *util_bridge_;
-}
diff --git a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h b/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h
deleted file mode 100644
index f317b71..0000000
--- a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_IMPL_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_IMPL_H_
-
-#include <jni.h>
-
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
-#include "chrome/browser/password_manager/android/password_manager_util_bridge_interface.h"
-
-class PasswordAccessLossWarningBridgeImpl
-    : public PasswordAccessLossWarningBridge {
- public:
-  PasswordAccessLossWarningBridgeImpl();
-  PasswordAccessLossWarningBridgeImpl(
-      const PasswordAccessLossWarningBridgeImpl&) = delete;
-  PasswordAccessLossWarningBridgeImpl& operator=(
-      const PasswordAccessLossWarningBridgeImpl&) = delete;
-  ~PasswordAccessLossWarningBridgeImpl() override;
-
-  bool ShouldShowAccessLossNoticeSheet(PrefService* pref_service,
-                                       bool called_at_startup) override;
-  void MaybeShowAccessLossNoticeSheet(
-      PrefService* pref_service,
-      const gfx::NativeWindow window,
-      Profile* profile,
-      bool called_at_startup,
-      password_manager_android_util::PasswordAccessLossWarningTriggers
-          trigger_source) override;
-
-  void SetUtilBridgeForTesting(
-      std::unique_ptr<
-          password_manager_android_util::PasswordManagerUtilBridgeInterface>
-          util_bridge);
-
- private:
-  std::unique_ptr<
-      password_manager_android_util::PasswordManagerUtilBridgeInterface>
-      util_bridge_;
-
-  password_manager_android_util::PasswordManagerUtilBridgeInterface&
-  GetUtilBridge();
-};
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ACCESS_LOSS_PASSWORD_ACCESS_LOSS_WARNING_BRIDGE_IMPL_H_
diff --git a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl_unittest.cc b/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl_unittest.cc
deleted file mode 100644
index ba0561b..0000000
--- a/chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl_unittest.cc
+++ /dev/null
@@ -1,158 +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/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
-
-#include "base/android/build_info.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/time/time.h"
-#include "chrome/browser/password_manager/android/mock_password_manager_util_bridge.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class PasswordAccessLossWarningBridgeImplTest : public testing::Test {
- public:
-  PasswordAccessLossWarningBridgeImplTest() {
-    // The access loss warning should not be shown to users without passwords in
-    // the profile store.
-    pref_service_.registry()->RegisterBooleanPref(
-        password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-    pref_service_.registry()->RegisterTimePref(
-        password_manager::prefs::
-            kPasswordAccessLossWarningShownAtStartupTimestamp,
-        base::Time());
-    pref_service_.registry()->RegisterTimePref(
-        password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-        base::Time());
-
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        getGMSVersionForTestSetUp(/*is_up_to_date=*/false));
-
-    // There were local passwords stored in the login database.
-    // The pref needs to be explicitly set for the warning to show up.
-    pref_service()->SetBoolean(
-        password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-
-    auto mock_util_bridge = std::make_unique<MockPasswordManagerUtilBridge>();
-    ON_CALL(*mock_util_bridge, IsInternalBackendPresent)
-        .WillByDefault(testing::Return(true));
-    bridge_.SetUtilBridgeForTesting(std::move(mock_util_bridge));
-  }
-
-  std::string getGMSVersionForTestSetUp(bool is_up_to_date) {
-    int min_version = password_manager::GetLocalUpmMinGmsVersion();
-    return base::NumberToString(is_up_to_date ? min_version : min_version - 1);
-  }
-
-  TestingPrefServiceSimple* pref_service() { return &pref_service_; }
-  PasswordAccessLossWarningBridgeImpl* bridge() { return &bridge_; }
-  base::test::TaskEnvironment* task_env() { return &task_env_; }
-
- private:
-  TestingPrefServiceSimple pref_service_;
-  PasswordAccessLossWarningBridgeImpl bridge_;
-  content::BrowserTaskEnvironment task_env_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-};
-
-TEST_F(PasswordAccessLossWarningBridgeImplTest,
-       ShouldNotShowWarningWithNoWarningType) {
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      getGMSVersionForTestSetUp(/*is_up_to_date=*/true));
-
-  EXPECT_FALSE(bridge()->ShouldShowAccessLossNoticeSheet(
-      pref_service(), /*called_at_startup=*/false));
-}
-
-TEST_F(PasswordAccessLossWarningBridgeImplTest,
-       ShouldNotShowWarningMoreThanDaily) {
-  pref_service()->SetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-      base::Time::Now());
-  pref_service()->SetTime(password_manager::prefs::
-                              kPasswordAccessLossWarningShownAtStartupTimestamp,
-                          base::Time::Now());
-  task_env()->FastForwardBy(base::Hours(1));
-
-  EXPECT_FALSE(bridge()->ShouldShowAccessLossNoticeSheet(
-      pref_service(), /*called_at_startup=*/false));
-}
-
-TEST_F(PasswordAccessLossWarningBridgeImplTest,
-       ShouldNotShowWarningOnStartupMaxOncePerWeek) {
-  pref_service()->SetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-      base::Time::Now());
-  pref_service()->SetTime(password_manager::prefs::
-                              kPasswordAccessLossWarningShownAtStartupTimestamp,
-                          base::Time::Now());
-  task_env()->FastForwardBy(base::Days(3));
-
-  EXPECT_FALSE(bridge()->ShouldShowAccessLossNoticeSheet(
-      pref_service(), /*called_at_startup=*/true));
-}
-
-TEST_F(PasswordAccessLossWarningBridgeImplTest,
-       ShouldShowWarningOnStartupWithAllThePreconditionsSatisfied) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
-
-  // Simulate that the sheet was shown on startup more than a week ago.
-  pref_service()->SetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-      base::Time::Now());
-  pref_service()->SetTime(password_manager::prefs::
-                              kPasswordAccessLossWarningShownAtStartupTimestamp,
-                          base::Time::Now());
-  task_env()->FastForwardBy(base::Days(8));
-
-  EXPECT_TRUE(bridge()->ShouldShowAccessLossNoticeSheet(
-      pref_service(), /*called_at_startup=*/true));
-}
-
-TEST_F(PasswordAccessLossWarningBridgeImplTest,
-       ShouldShowWarningWithAllThePreconditionsSatisfied) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
-
-  // Simulate that the sheet was shown on startup two days ago so it can be
-  // shown again from an entry point which is not startup.
-  pref_service()->SetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-      base::Time::Now());
-  pref_service()->SetTime(password_manager::prefs::
-                              kPasswordAccessLossWarningShownAtStartupTimestamp,
-                          base::Time::Now());
-  task_env()->FastForwardBy(base::Days(2));
-
-  EXPECT_TRUE(bridge()->ShouldShowAccessLossNoticeSheet(
-      pref_service(), /*called_at_startup=*/false));
-}
-
-TEST_F(PasswordAccessLossWarningBridgeImplTest,
-       ShouldNotShowIfLoginDbDeprecationStarted) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      password_manager::features::kLoginDbDeprecationAndroid);
-
-  // Create all the conditions necessary for the sheet to show to verify that
-  // the reason it doesn't show is the login DB deprecation being enabled.
-  pref_service()->SetTime(
-      password_manager::prefs::kPasswordAccessLossWarningShownTimestamp,
-      base::Time::Now());
-  pref_service()->SetTime(password_manager::prefs::
-                              kPasswordAccessLossWarningShownAtStartupTimestamp,
-                          base::Time::Now());
-  task_env()->FastForwardBy(base::Days(2));
-
-  EXPECT_FALSE(bridge()->ShouldShowAccessLossNoticeSheet(
-      pref_service(), /*called_at_startup=*/false));
-}
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc
index df4e8a2d..20f482d7 100644
--- a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <vector>
 
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/plus_addresses/plus_address_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -41,8 +40,7 @@
     FocusedFieldType focused_field_type,
     PasswordManagerClient* client,
     PasswordReuseDetectionManagerClient*
-        password_reuse_detection_manager_client,
-    std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge)
+        password_reuse_detection_manager_client)
     : view_(std::move(view)),
       web_contents_(web_contents),
       profile_store_(profile_store),
@@ -53,7 +51,6 @@
       client_(client),
       password_reuse_detection_manager_client_(
           password_reuse_detection_manager_client),
-      access_loss_warning_bridge_(std::move(access_loss_warning_bridge)),
       plus_address_service_(PlusAddressServiceFactory::GetForBrowserContext(
           web_contents_->GetBrowserContext())) {}
 
@@ -69,8 +66,6 @@
       account_store_(account_store),
       dismissal_callback_(std::move(dismissal_callback)),
       focused_field_type_(focused_field_type),
-      access_loss_warning_bridge_(
-          std::make_unique<PasswordAccessLossWarningBridgeImpl>()),
       plus_address_service_(PlusAddressServiceFactory::GetForBrowserContext(
           web_contents_->GetBrowserContext())) {
   CHECK(web_contents_);
@@ -163,8 +158,6 @@
     driver_->FillIntoFocusedField(is_password_field, username);
   }
 
-  TryToShowAccessLossWarningSheet();
-
   // Consumes the dismissal callback to destroy the native controller and java
   // controller after the user selects a credential.
   OnDismiss();
@@ -191,7 +184,6 @@
 
   if (auth_succeeded) {
     FillPassword(password);
-    TryToShowAccessLossWarningSheet();
   }
 
   // Consumes the dismissal callback to destroy the native controller and java
@@ -221,16 +213,3 @@
   }
   view_->Show(std::move(results[0]), focused_field_type_);
 }
-
-void AllPasswordsBottomSheetController::TryToShowAccessLossWarningSheet() {
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
-  if (profile && access_loss_warning_bridge_->ShouldShowAccessLossNoticeSheet(
-                     profile->GetPrefs(), /*called_at_startup=*/false)) {
-    access_loss_warning_bridge_->MaybeShowAccessLossNoticeSheet(
-        profile->GetPrefs(), web_contents_->GetTopLevelNativeWindow(), profile,
-        /*called_at_startup=*/false,
-        password_manager_android_util::PasswordAccessLossWarningTriggers::
-            kAllPasswords);
-  }
-}
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h
index 6b6c86e..67591ec 100644
--- a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h
@@ -11,7 +11,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/types/pass_key.h"
 #include "base/types/strong_alias.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom-forward.h"
 #include "components/device_reauth/device_authenticator.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -58,9 +57,7 @@
       autofill::mojom::FocusedFieldType focused_field_type,
       password_manager::PasswordManagerClient* client,
       safe_browsing::PasswordReuseDetectionManagerClient*
-          password_reuse_detection_manager_client,
-      std::unique_ptr<PasswordAccessLossWarningBridge>
-          access_loss_warning_bridge);
+          password_reuse_detection_manager_client);
 
   AllPasswordsBottomSheetController(
       content::WebContents* web_contents,
@@ -116,10 +113,6 @@
       std::vector<std::vector<std::unique_ptr<password_manager::PasswordForm>>>
           results);
 
-  // Shows the access loss warning sheet if needed. It's used after filling a
-  // credential.
-  void TryToShowAccessLossWarningSheet();
-
   // The controller takes |view_| ownership.
   std::unique_ptr<AllPasswordsBottomSheetView> view_;
 
@@ -160,10 +153,6 @@
   raw_ptr<safe_browsing::PasswordReuseDetectionManagerClient>
       password_reuse_detection_manager_client_ = nullptr;
 
-  // Bridge that is used to show the password access loss warning if it's needed
-  // after filling a credential.
-  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge_;
-
   // `PlusAddressService` is used to check which credentials have a plus address
   // as a username.
   raw_ptr<const plus_addresses::PlusAddressService> plus_address_service_;
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc
index ab958e9b..282933f87 100644
--- a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/types/pass_key.h"
-#include "chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.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/passwords/all_passwords_bottom_sheet_view.h"
@@ -157,9 +156,6 @@
     std::unique_ptr<MockAllPasswordsBottomSheetView> mock_view_unique_ptr =
         std::make_unique<MockAllPasswordsBottomSheetView>();
     mock_view_ = mock_view_unique_ptr.get();
-    auto access_loss_bridge =
-        std::make_unique<MockPasswordAccessLossWarningBridge>();
-    mock_access_loss_warning_bridge_ = access_loss_bridge.get();
     all_passwords_controller_ =
         std::make_unique<AllPasswordsBottomSheetController>(
             base::PassKey<AllPasswordsBottomSheetControllerTest>(),
@@ -167,8 +163,7 @@
             driver_.AsWeakPtr(), profile_store_.get(), account_store_.get(),
             dissmissal_callback_.Get(), focused_field_type,
             mock_pwd_manager_client_.get(),
-            mock_pwd_reuse_detection_manager_client_.get(),
-            std::move(access_loss_bridge));
+            mock_pwd_reuse_detection_manager_client_.get());
   }
 
   std::unique_ptr<KeyedService> PlusAddressServiceTestFactory(
@@ -208,10 +203,6 @@
     return *mock_pwd_reuse_detection_manager_client_.get();
   }
 
-  MockPasswordAccessLossWarningBridge* mock_access_loss_warning_bridge() {
-    return mock_access_loss_warning_bridge_;
-  }
-
  protected:
   MockPasswordManagerDriver driver_;
   scoped_refptr<TestPasswordStore> profile_store_;
@@ -226,7 +217,6 @@
       mock_pwd_reuse_detection_manager_client_ =
           std::make_unique<MockPasswordReuseDetectionManagerClient>();
   base::test::ScopedFeatureList scoped_feature_list_;
-  raw_ptr<MockPasswordAccessLossWarningBridge> mock_access_loss_warning_bridge_;
 };
 
 TEST_F(AllPasswordsBottomSheetControllerTest, Show) {
@@ -415,72 +405,6 @@
       kUsername1, kPassword, RequestsToFillPassword(true));
 }
 
-TEST_F(AllPasswordsBottomSheetControllerTest,
-       ShowAccessLossWarningOnUsernameFill) {
-  createAllPasswordsController(FocusedFieldType::kFillableUsernameField);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet(
-                  profile()->GetPrefs(), _, profile(),
-                  /*called_at_startup=*/false,
-                  password_manager_android_util::
-                      PasswordAccessLossWarningTriggers::kAllPasswords));
-  all_passwords_controller()->OnCredentialSelected(
-      kUsername1, kPassword, RequestsToFillPassword(false));
-}
-
-TEST_F(AllPasswordsBottomSheetControllerTest,
-       ShowAccessLossWarningAfterReauthOnPasswordFill) {
-  auto mock_authenticator =
-      std::make_unique<device_reauth::MockDeviceAuthenticator>();
-  EXPECT_CALL(*mock_authenticator, AuthenticateWithMessage)
-      .WillOnce([](const std::u16string&,
-                   device_reauth::DeviceAuthenticator::AuthenticateCallback
-                       callback) { std::move(callback).Run(true); });
-  EXPECT_CALL(client(), GetDeviceAuthenticator)
-      .WillOnce(Return(testing::ByMove(std::move(mock_authenticator))));
-  EXPECT_CALL(client(), IsReauthBeforeFillingRequired).WillOnce(Return(true));
-
-  createAllPasswordsController(FocusedFieldType::kFillablePasswordField);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet(
-                  profile()->GetPrefs(), _, profile(),
-                  /*called_at_startup=*/false,
-                  password_manager_android_util::
-                      PasswordAccessLossWarningTriggers::kAllPasswords));
-  all_passwords_controller()->OnCredentialSelected(
-      kUsername1, kPassword, RequestsToFillPassword(true));
-}
-
-TEST_F(AllPasswordsBottomSheetControllerTest,
-       ShowAccessLossWarningWithoutReauthOnPasswordFill) {
-  // Skipped for automotive because reauthentication is always needed there.
-  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
-    GTEST_SKIP();
-  }
-
-  createAllPasswordsController(FocusedFieldType::kFillablePasswordField);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet(
-                  profile()->GetPrefs(), _, profile(),
-                  /*called_at_startup=*/false,
-                  password_manager_android_util::
-                      PasswordAccessLossWarningTriggers::kAllPasswords));
-  all_passwords_controller()->OnCredentialSelected(
-      kUsername1, kPassword, RequestsToFillPassword(true));
-}
-
 TEST_F(AllPasswordsBottomSheetControllerTest, IsPlusAddress) {
   scoped_feature_list_.Reset();
   scoped_feature_list_.InitWithFeatures(
diff --git a/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.cc b/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.cc
deleted file mode 100644
index a4493ee..0000000
--- a/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.cc
+++ /dev/null
@@ -1,562 +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 "chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h"
-
-#include <optional>
-#include <string>
-#include <variant>
-
-#include "base/barrier_callback.h"
-#include "base/containers/flat_set.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/strcat.h"
-#include "base/trace_event/trace_event.h"
-#include "chrome/browser/password_manager/android/password_store_android_backend.h"
-#include "chrome/browser/password_manager/android/password_store_android_backend_api_error_codes.h"
-#include "components/browser_sync/sync_to_signin_migration.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_form.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend_error.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/public/base/signin_pref_names.h"
-#include "components/sync/base/pref_names.h"
-
-namespace password_manager {
-
-namespace {
-
-// Threshold for the next migration attempt. This is needed in order to prevent
-// clients from spamming GMS Core API.
-constexpr base::TimeDelta kMigrationThreshold = base::Days(1);
-
-// The required migration version. If the version saved in
-// `prefs::kCurrentMigrationVersionToGoogleMobileServices` is lower than
-// 'kRequiredMigrationVersion', passwords will be re-uploaded. Currently set to
-// the initial migration version.
-constexpr int kRequiredMigrationVersion = 1;
-
-constexpr char kMetricInfix[] =
-    "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.";
-
-// Returns true if the initial migration to the android backend has happened.
-bool HasMigratedToTheAndroidBackend(PrefService* prefs) {
-  return prefs->GetInteger(
-             prefs::kCurrentMigrationVersionToGoogleMobileServices) >=
-         kRequiredMigrationVersion;
-}
-
-bool IsBlocklistedFormWithValues(const PasswordForm& form) {
-  return form.blocked_by_user &&
-         (!form.username_value.empty() || !form.password_value.empty());
-}
-
-std::string BackendOperationToString(
-    BuiltInBackendToAndroidBackendMigrator::BackendOperationForMigration
-        backend_operation) {
-  switch (backend_operation) {
-    case BuiltInBackendToAndroidBackendMigrator::BackendOperationForMigration::
-        kAddLogin:
-      return "AddLogin";
-    case BuiltInBackendToAndroidBackendMigrator::BackendOperationForMigration::
-        kUpdateLogin:
-      return "UpdateLogin";
-    case BuiltInBackendToAndroidBackendMigrator::BackendOperationForMigration::
-        kRemoveLogin:
-      return "RemoveLogin";
-    case BuiltInBackendToAndroidBackendMigrator::BackendOperationForMigration::
-        kGetAllLogins:
-      return "GetAllLogins";
-  }
-}
-
-void ResetUnenrollmentStatus(PrefService* prefs) {
-  prefs->ClearPref(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors);
-}
-
-bool IsPasswordSyncEnabled(PrefService* pref_service) {
-  switch (browser_sync::GetSyncToSigninMigrationDataTypeDecision(
-      pref_service, syncer::PASSWORDS,
-      syncer::prefs::internal::kSyncPasswords)) {
-    // In particular, in the
-    // prefs::UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending
-    // state, kDontMigrateTypeNotActive is reported and we wish to return true.
-    case browser_sync::SyncToSigninMigrationDataTypeDecision::
-        kDontMigrateTypeNotActive:
-    case browser_sync::SyncToSigninMigrationDataTypeDecision::kMigrate:
-      return true;
-    case browser_sync::SyncToSigninMigrationDataTypeDecision::
-        kDontMigrateTypeDisabled:
-      return false;
-  }
-}
-
-void SchedulePostMigrationBottomSheet(PrefService* prefs) {
-  // There is no need to show the sheet if no passwords were migrated.
-  if (prefs->GetBoolean(prefs::kEmptyProfileStoreLoginDatabase)) {
-    return;
-  }
-
-  // As part of M4 syncing users who were unenrolled migrate their passwords to
-  // local GMSCore storage. They shouldn't see the sheet either.
-  if (IsPasswordSyncEnabled(prefs) &&
-      (prefs->GetBoolean(
-           prefs::kUnenrolledFromGoogleMobileServicesDueToErrors) ||
-       prefs->GetInteger(
-           prefs::kCurrentMigrationVersionToGoogleMobileServices) == 0)) {
-    return;
-  }
-
-  prefs->SetBoolean(prefs::kShouldShowPostPasswordMigrationSheetAtStartup,
-                    true);
-}
-
-}  // namespace
-
-struct BuiltInBackendToAndroidBackendMigrator::IsPasswordLess {
-  bool operator()(const PasswordForm* lhs, const PasswordForm* rhs) const {
-    return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
-  }
-};
-
-struct BuiltInBackendToAndroidBackendMigrator::BackendAndLoginsResults {
-  raw_ptr<PasswordStoreBackend> backend;
-  LoginsResultOrError logins_result;
-
-  bool HasError() const {
-    return std::holds_alternative<PasswordStoreBackendError>(logins_result);
-  }
-
-  std::optional<int> GetApiError() const {
-    if (HasError()) {
-      return std::get<PasswordStoreBackendError>(logins_result)
-          .android_backend_api_error;
-    }
-    return std::nullopt;
-  }
-
-  // Converts std::vector<std::unique_ptr<PasswordForms>> into
-  // base::flat_set<const PasswordForm*> for quick look up comparing only
-  // primary keys.
-  base::flat_set<const PasswordForm*, IsPasswordLess> GetLogins() {
-    DCHECK(!HasError());
-
-    return base::MakeFlatSet<const PasswordForm*, IsPasswordLess>(
-        std::get<LoginsResult>(logins_result), {},
-        [](auto& form) { return &form; });
-  }
-
-  BackendAndLoginsResults(PasswordStoreBackend* backend,
-                          LoginsResultOrError logins)
-      : backend(backend), logins_result(std::move(logins)) {}
-  BackendAndLoginsResults(BackendAndLoginsResults&&) = default;
-  BackendAndLoginsResults& operator=(BackendAndLoginsResults&&) = default;
-  BackendAndLoginsResults(const BackendAndLoginsResults&) = delete;
-  BackendAndLoginsResults& operator=(const BackendAndLoginsResults&) = delete;
-  ~BackendAndLoginsResults() = default;
-};
-
-class BuiltInBackendToAndroidBackendMigrator::MigrationMetricsReporter {
- public:
-  MigrationMetricsReporter() = default;
-  ~MigrationMetricsReporter() = default;
-
-  void ReportMetrics(bool migration_succeeded) {
-    base::TimeDelta duration = base::Time::Now() - start_;
-    base::UmaHistogramMediumTimes(base::StrCat({kMetricInfix, "Latency"}),
-                                  duration);
-    base::UmaHistogramBoolean(base::StrCat({kMetricInfix, "Success"}),
-                              migration_succeeded);
-    base::UmaHistogramCounts1000(
-        base::StrCat({kMetricInfix, "UpdateLoginCount"}), update_logins_count_);
-    ReportAdditionalMetricsForLocalPasswordsMigration(migration_succeeded);
-    metrics_util::LogLocalPwdMigrationProgressState(
-        metrics_util::LocalPwdMigrationProgressState::kFinished);
-  }
-
-  void ReportAdditionalMetricsForLocalPasswordsMigration(
-      bool migration_succeeded) {
-    base::UmaHistogramCounts1000(base::StrCat({kMetricInfix, "AddLoginCount"}),
-                                 added_logins_count_);
-    base::UmaHistogramCounts1000(
-        base::StrCat({kMetricInfix, "MigratedLoginsTotalCount"}),
-        added_logins_count_ + update_logins_count_);
-    if (migration_succeeded &&
-        migration_conflict_won_by_android_count_.has_value()) {
-      base::UmaHistogramCounts1000(
-          base::StrCat({kMetricInfix, "MergeWhereAndroidHasMostRecent"}),
-          migration_conflict_won_by_android_count_.value());
-    }
-  }
-
-  void HandleBackendOperationResult(
-      std::string backend_infix,
-      BackendOperationForMigration backend_operation,
-      bool is_success,
-      std::optional<int> api_error) {
-    base::UmaHistogramBoolean(
-        base::StrCat({kMetricInfix, backend_infix, ".",
-                      BackendOperationToString(backend_operation), ".Success"}),
-        is_success);
-    if (!is_success) {
-      if (api_error.has_value()) {
-        base::UmaHistogramSparse(
-            base::StrCat({kMetricInfix, backend_infix, ".",
-                          BackendOperationToString(backend_operation),
-                          ".APIError"}),
-            api_error.value());
-      }
-      return;
-    }
-
-    switch (backend_operation) {
-      case BackendOperationForMigration::kAddLogin:
-        added_logins_count_++;
-        break;
-      case BackendOperationForMigration::kUpdateLogin:
-        update_logins_count_++;
-        break;
-      case BackendOperationForMigration::kRemoveLogin:
-      case BackendOperationForMigration::kGetAllLogins:
-        break;
-    }
-  }
-
-  void SetLocalConflictsWonByAndroidCount(int count) {
-    migration_conflict_won_by_android_count_ = count;
-  }
-
- private:
-  base::Time start_ = base::Time::Now();
-  std::optional<int> migration_conflict_won_by_android_count_;
-  int added_logins_count_ = 0;
-  int update_logins_count_ = 0;
-};
-
-BuiltInBackendToAndroidBackendMigrator::BuiltInBackendToAndroidBackendMigrator(
-    PasswordStoreBackend* built_in_backend,
-    PasswordStoreBackend* android_backend,
-    PrefService* prefs)
-    : built_in_backend_(built_in_backend),
-      android_backend_(android_backend),
-      prefs_(prefs) {
-  DCHECK(built_in_backend_);
-  DCHECK(android_backend_);
-  base::UmaHistogramBoolean(
-      "PasswordManager.UnifiedPasswordManager.WasMigrationDone",
-      HasMigratedToTheAndroidBackend(prefs_));
-}
-
-BuiltInBackendToAndroidBackendMigrator::
-    ~BuiltInBackendToAndroidBackendMigrator() = default;
-
-void BuiltInBackendToAndroidBackendMigrator::StartMigrationOfLocalPasswords() {
-  CHECK(!migration_in_progress_);
-
-  // Don't try to migrate passwords if there was an attempt earlier today.
-  base::TimeDelta time_passed_since_last_migration_attempt =
-      base::Time::Now() -
-      base::Time::FromTimeT(prefs_->GetDouble(
-          password_manager::prefs::kTimeOfLastMigrationAttempt));
-  if (time_passed_since_last_migration_attempt < kMigrationThreshold) {
-    return;
-  }
-
-  migration_in_progress_ = true;
-
-  metrics_reporter_ = std::make_unique<MigrationMetricsReporter>();
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("passwords",
-                                    "UnifiedPasswordManagerMigration", this);
-
-  prefs_->SetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt,
-                    base::Time::Now().InSecondsFSinceUnixEpoch());
-
-  LogLocalPwdMigrationProgressState(
-      metrics_util::LocalPwdMigrationProgressState::kStarted);
-  auto barrier_callback = base::BarrierCallback<BackendAndLoginsResults>(
-      2,
-      base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::
-                         MigrateLocalPasswordsBetweenAndroidAndBuiltInBackends,
-                     weak_ptr_factory_.GetWeakPtr()));
-
-  auto bind_backend_to_logins = [](PasswordStoreBackend* backend,
-                                   LoginsResultOrError result) {
-    return BackendAndLoginsResults(backend, std::move(result));
-  };
-
-  auto builtin_backend_callback_chain =
-      base::BindOnce(bind_backend_to_logins,
-                     base::Unretained(built_in_backend_))
-          .Then(barrier_callback);
-
-  // Cleanup blacklisted forms in the built in backend before binding.
-  builtin_backend_callback_chain = base::BindOnce(
-      &BuiltInBackendToAndroidBackendMigrator::RemoveBlocklistedFormsWithValues,
-      weak_ptr_factory_.GetWeakPtr(), base::Unretained(built_in_backend_),
-      std::move(builtin_backend_callback_chain));
-
-  built_in_backend_->GetAllLoginsAsync(
-      std::move(builtin_backend_callback_chain));
-
-  auto android_backend_callback_chain =
-      base::BindOnce(bind_backend_to_logins, base::Unretained(android_backend_))
-          .Then(barrier_callback);
-
-  // Cleanup blacklisted forms in the android backend before binding.
-  android_backend_callback_chain = base::BindOnce(
-      &BuiltInBackendToAndroidBackendMigrator::RemoveBlocklistedFormsWithValues,
-      weak_ptr_factory_.GetWeakPtr(), base::Unretained(android_backend_),
-      std::move(android_backend_callback_chain));
-
-  android_backend_->GetAllLoginsAsync(
-      std::move(android_backend_callback_chain));
-}
-
-void BuiltInBackendToAndroidBackendMigrator::OnSyncServiceInitialized(
-    syncer::SyncService* sync_service) {
-  sync_service_ = sync_service;
-}
-
-base::WeakPtr<BuiltInBackendToAndroidBackendMigrator>
-BuiltInBackendToAndroidBackendMigrator::GetWeakPtr() {
-  return weak_ptr_factory_.GetWeakPtr();
-}
-
-void BuiltInBackendToAndroidBackendMigrator::
-    MigrateLocalPasswordsBetweenAndroidAndBuiltInBackends(
-        std::vector<BackendAndLoginsResults> results) {
-  DCHECK(metrics_reporter_);
-  DCHECK_EQ(2u, results.size());
-
-  if (results[0].HasError() || results[1].HasError()) {
-    for (const auto& result : results) {
-      metrics_reporter_->HandleBackendOperationResult(
-          GetMetricInfixFromBackend(result.backend),
-          BackendOperationForMigration::kGetAllLogins, !result.HasError(),
-          result.GetApiError());
-    }
-
-    MigrationFinished(/*is_success=*/false);
-    return;
-  }
-
-  base::flat_set<const PasswordForm*, IsPasswordLess> built_in_backend_logins =
-      (results[0].backend == built_in_backend_) ? results[0].GetLogins()
-                                                : results[1].GetLogins();
-
-  base::flat_set<const PasswordForm*, IsPasswordLess> android_logins =
-      (results[0].backend == android_backend_) ? results[0].GetLogins()
-                                               : results[1].GetLogins();
-
-  MergeBuiltInBackendIntoAndroidBackend(std::move(built_in_backend_logins),
-                                        std::move(android_logins));
-}
-
-void BuiltInBackendToAndroidBackendMigrator::
-    MergeBuiltInBackendIntoAndroidBackend(
-        PasswordFormPtrFlatSet built_in_backend_logins,
-        PasswordFormPtrFlatSet android_logins) {
-  // For a form |F|, there are 2 cases to handle:
-  // 1. If |F| exists only in the |built_in_backend_|, then |F| should be added
-  //    to the |android_backend_|.
-  // 2. If |F| already exists in both |android_backend_|, then
-  //    the most recent version of |F| will be kept in |android_backend_|.
-  // No changes are made to the |built_in_backend_|.
-
-  // Callbacks are chained like in a stack way by passing 'callback_chain' as a
-  // completion for the next operation. At the end, update pref to mark
-  // successful completion.
-  base::OnceClosure callbacks_chain =
-      base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::MigrationFinished,
-                     weak_ptr_factory_.GetWeakPtr(), /*is_success=*/true);
-  int migration_conflict_won_by_android_count = 0;
-  for (auto* const login : built_in_backend_logins) {
-    auto android_login_iter = android_logins.find(login);
-
-    if (android_login_iter == android_logins.end()) {
-      // Password from the |built_in_backend_| doesn't exist in the
-      // |android_backend_|.
-      callbacks_chain = base::BindOnce(
-          &BuiltInBackendToAndroidBackendMigrator::AddLoginToBackend,
-          weak_ptr_factory_.GetWeakPtr(), android_backend_, *login,
-          std::move(callbacks_chain));
-
-      continue;
-    }
-
-    // Password from the |built_in_backend_| exists in the |android_backend_|.
-    auto* const android_login = (*android_login_iter);
-
-    if (login->password_value == android_login->password_value) {
-      // Passwords are identical, nothing else to do.
-      continue;
-    }
-
-    // Passwords aren't identical. Pick the most recentl one. The most recent is
-    // considered the one, which has the newest create, last used or modified
-    // date.
-    if (std::max({login->date_created, login->date_last_used,
-                  login->date_password_modified}) >
-        std::max({android_login->date_created, android_login->date_last_used,
-                  android_login->date_password_modified})) {
-      callbacks_chain = base::BindOnce(
-          &BuiltInBackendToAndroidBackendMigrator::UpdateLoginInBackend,
-          weak_ptr_factory_.GetWeakPtr(), android_backend_, *login,
-          std::move(callbacks_chain));
-    } else {
-      migration_conflict_won_by_android_count++;
-    }
-  }
-  metrics_reporter_->SetLocalConflictsWonByAndroidCount(
-      migration_conflict_won_by_android_count);
-  std::move(callbacks_chain).Run();
-}
-
-void BuiltInBackendToAndroidBackendMigrator::AddLoginToBackend(
-    PasswordStoreBackend* backend,
-    const PasswordForm& form,
-    base::OnceClosure callback) {
-  backend->AddLoginAsync(
-      form,
-      base::BindOnce(
-          &BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration,
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-          GetMetricInfixFromBackend(backend),
-          BackendOperationForMigration::kAddLogin));
-}
-
-void BuiltInBackendToAndroidBackendMigrator::UpdateLoginInBackend(
-    PasswordStoreBackend* backend,
-    const PasswordForm& form,
-    base::OnceClosure callback) {
-  backend->UpdateLoginAsync(
-      form,
-      base::BindOnce(
-          &BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration,
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-          GetMetricInfixFromBackend(backend),
-          BackendOperationForMigration::kUpdateLogin));
-}
-
-void BuiltInBackendToAndroidBackendMigrator::RemoveLoginFromBackend(
-    PasswordStoreBackend* backend,
-    const PasswordForm& form,
-    base::OnceClosure callback) {
-  backend->RemoveLoginAsync(
-      FROM_HERE, form,
-      base::BindOnce(
-          &BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration,
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-          GetMetricInfixFromBackend(backend),
-          BackendOperationForMigration::kRemoveLogin));
-}
-
-void BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration(
-    base::OnceClosure callback,
-    const std::string& backend_infix,
-    BackendOperationForMigration backend_operation,
-    PasswordChangesOrError changes_or_error) {
-  if (std::holds_alternative<PasswordStoreBackendError>(changes_or_error)) {
-    const PasswordStoreBackendError& error =
-        std::get<PasswordStoreBackendError>(changes_or_error);
-    metrics_reporter_->HandleBackendOperationResult(
-        backend_infix, backend_operation, /*is_success=*/false,
-        error.android_backend_api_error);
-    MigrationFinished(/*is_success=*/false);
-    return;
-  }
-
-  const PasswordChanges& changes = std::get<PasswordChanges>(changes_or_error);
-  // Nullopt changelist is returned on success by the backends that do not
-  // provide exact changelist (e.g. Android). This indicates success operation
-  // as well as non-empty changelist.
-  if (!changes.has_value() || !changes.value().empty()) {
-    metrics_reporter_->HandleBackendOperationResult(backend_infix,
-                                                    backend_operation,
-                                                    /*is_success=*/true,
-                                                    /*api_error=*/std::nullopt);
-    // The step was successful, continue the migration.
-    std::move(callback).Run();
-    return;
-  }
-
-  // Migration failed.
-  // It is unclear what the reason for this could be, but since there
-  // was technically no API error, there is none to record.
-  metrics_reporter_->HandleBackendOperationResult(
-      backend_infix, backend_operation, /*is_success=*/false,
-      /*api_error=*/std::nullopt);
-  MigrationFinished(/*is_success=*/false);
-}
-
-void BuiltInBackendToAndroidBackendMigrator::MigrationFinished(
-    bool is_success) {
-  DCHECK(metrics_reporter_);
-  metrics_reporter_->ReportMetrics(is_success);
-  metrics_reporter_.reset();
-
-  if (is_success && migration_in_progress_) {
-    SchedulePostMigrationBottomSheet(prefs_);
-    prefs_->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                       kRequiredMigrationVersion);
-    ResetUnenrollmentStatus(prefs_);
-    prefs_->SetInteger(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
-  }
-
-  migration_in_progress_ = false;
-  TRACE_EVENT_NESTABLE_ASYNC_END0("passwords",
-                                  "UnifiedPasswordManagerMigration", this);
-}
-
-void BuiltInBackendToAndroidBackendMigrator::RemoveBlocklistedFormsWithValues(
-    PasswordStoreBackend* backend,
-    LoginsOrErrorReply result_callback,
-    LoginsResultOrError logins_or_error) {
-  if (std::holds_alternative<PasswordStoreBackendError>(logins_or_error)) {
-    std::move(result_callback).Run(std::move(logins_or_error));
-    return;
-  }
-
-  LoginsResult all_forms = std::get<LoginsResult>(std::move(logins_or_error));
-  LoginsResult clean_forms;
-  LoginsResult forms_to_remove;
-  clean_forms.reserve(all_forms.size());
-  forms_to_remove.reserve(all_forms.size());
-
-  for (auto& form : all_forms) {
-    if (IsBlocklistedFormWithValues(form)) {
-      forms_to_remove.push_back(std::move(form));
-    } else {
-      clean_forms.push_back(std::move(form));
-    }
-  }
-
-  auto callback_chain =
-      base::BindOnce(std::move(result_callback), std::move(clean_forms));
-
-  for (auto& form : forms_to_remove) {
-    callback_chain = base::BindOnce(
-        &BuiltInBackendToAndroidBackendMigrator::RemoveLoginFromBackend,
-        weak_ptr_factory_.GetWeakPtr(), backend, form,
-        std::move(callback_chain));
-  }
-
-  std::move(callback_chain).Run();
-}
-
-std::string BuiltInBackendToAndroidBackendMigrator::GetMetricInfixFromBackend(
-    PasswordStoreBackend* backend) {
-  return backend == built_in_backend_ ? "BuiltInBackend" : "AndroidBackend";
-}
-
-}  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h b/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h
deleted file mode 100644
index 1118f93..0000000
--- a/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h
+++ /dev/null
@@ -1,132 +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.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_BUILT_IN_BACKEND_TO_ANDROID_BACKEND_MIGRATOR_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_BUILT_IN_BACKEND_TO_ANDROID_BACKEND_MIGRATOR_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-
-class PrefService;
-
-namespace password_manager {
-
-// Instantiate this object to migrate all stored passwords between the built-in
-// and the Android backends. Migration is potentially an expensive operation
-// and shouldn't start during the hot phase of Chrome start.
-class BuiltInBackendToAndroidBackendMigrator {
- public:
-  // The type of operation triggered on backend during the migration. Used for
-  // the metrics reporting.
-  enum class BackendOperationForMigration {
-    kAddLogin,
-    kUpdateLogin,
-    kRemoveLogin,
-    kGetAllLogins,
-  };
-
-  // |built_in_backend| and |android_backend| must not be null and must outlive
-  // the migrator.
-  BuiltInBackendToAndroidBackendMigrator(PasswordStoreBackend* built_in_backend,
-                                         PasswordStoreBackend* android_backend,
-                                         PrefService* prefs);
-
-  BuiltInBackendToAndroidBackendMigrator(
-      const BuiltInBackendToAndroidBackendMigrator&) = delete;
-  BuiltInBackendToAndroidBackendMigrator& operator=(
-      const BuiltInBackendToAndroidBackendMigrator&) = delete;
-  BuiltInBackendToAndroidBackendMigrator(
-      BuiltInBackendToAndroidBackendMigrator&&) = delete;
-  BuiltInBackendToAndroidBackendMigrator& operator=(
-      BuiltInBackendToAndroidBackendMigrator&&) = delete;
-  ~BuiltInBackendToAndroidBackendMigrator();
-
-  // Starts migration from |built_in_backend| to |android_backend| if time from
-  // last attempt is enough.
-  void StartMigrationOfLocalPasswords();
-
-  void OnSyncServiceInitialized(syncer::SyncService* sync_service);
-
-  bool migration_in_progress() const { return migration_in_progress_; }
-
-  base::WeakPtr<BuiltInBackendToAndroidBackendMigrator> GetWeakPtr();
-
- private:
-  struct IsPasswordLess;
-  struct BackendAndLoginsResults;
-  class MigrationMetricsReporter;
-
-  using PasswordFormPtrFlatSet =
-      base::flat_set<const PasswordForm*, IsPasswordLess>;
-
-  // Migrates password from the profile store |built_in_backend_| to the Gms
-  // core local store |android_backend_|. |result| consists of passwords from
-  // the |built_in_backend_| let's call them |A|. If the password from |A| is
-  // already present in |android_backend_|, then the latest version of the
-  // credential is adopted by |android_backend_|.
-  void MigrateLocalPasswordsBetweenAndroidAndBuiltInBackends(
-      std::vector<BackendAndLoginsResults> result);
-
-  // Updates both |built_in_backend_| and |android_backend_| such that both
-  // contain the same set of passwords without deleting any password. In
-  // addition, it marks the initial migration as completed.
-  void MergeBuiltInBackendIntoAndroidBackend(
-      PasswordFormPtrFlatSet built_in_backend_logins,
-      PasswordFormPtrFlatSet android_logins);
-
-  // Helper methods to {Add,Update,Remove} |form| in |backend|. This is used to
-  // ensure that all the operations are happening inside
-  // BuiltInBackendToAndroidBackendMigrator life-scope.
-  void AddLoginToBackend(PasswordStoreBackend* backend,
-                         const PasswordForm& form,
-                         base::OnceClosure callback);
-  void UpdateLoginInBackend(PasswordStoreBackend* backend,
-                            const PasswordForm& form,
-                            base::OnceClosure callback);
-  void RemoveLoginFromBackend(PasswordStoreBackend* backend,
-                              const PasswordForm& form,
-                              base::OnceClosure callback);
-
-  // If |changelist| is an empty changelist, migration is aborted by calling
-  // MigrationFinished() indicating the migration is *not* successful.
-  // Otherwise, |callback| is invoked. |backend| is used to know on which
-  // backend the operation was performed, for the purpose of recording metrics.
-  void RunCallbackOrAbortMigration(
-      base::OnceClosure callback,
-      const std::string& backend_infix,
-      BackendOperationForMigration backend_operation,
-      PasswordChangesOrError changelist);
-
-  // Reports metrics and deletes |metrics_reporter_|
-  void MigrationFinished(bool is_success);
-
-  // Removes blocklisted forms with non-empty |username_value| or
-  // |password_value| from |backend|.
-  // |result_callback| is called with the |LoginsResult| containing valid forms
-  // only or |PasswordStoreBackendError| if it contained in |logins_or_error|.
-  // |logins_or_error| is modified in place.
-  void RemoveBlocklistedFormsWithValues(PasswordStoreBackend* backend,
-                                        LoginsOrErrorReply result_callback,
-                                        LoginsResultOrError logins_or_error);
-
-  // Returns the string to be used in recording metrics for this |backend|.
-  std::string GetMetricInfixFromBackend(PasswordStoreBackend* backend);
-
-  const raw_ptr<PasswordStoreBackend> built_in_backend_;
-  const raw_ptr<PasswordStoreBackend> android_backend_;
-  const raw_ptr<PrefService> prefs_;
-
-  std::unique_ptr<MigrationMetricsReporter> metrics_reporter_;
-
-  raw_ptr<const syncer::SyncService> sync_service_ = nullptr;
-
-  bool migration_in_progress_ = false;
-
-  base::WeakPtrFactory<BuiltInBackendToAndroidBackendMigrator>
-      weak_ptr_factory_{this};
-};
-
-}  // namespace password_manager
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_BUILT_IN_BACKEND_TO_ANDROID_BACKEND_MIGRATOR_H_
diff --git a/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator_unittest.cc b/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator_unittest.cc
deleted file mode 100644
index 34e0329..0000000
--- a/chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator_unittest.cc
+++ /dev/null
@@ -1,1059 +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 "chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h"
-
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/test/gmock_callback_support.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "base/time/time.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "components/password_manager/core/browser/password_store/fake_password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/mock_password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/public/base/signin_pref_names.h"
-#include "components/sync/base/pref_names.h"
-#include "components/sync/service/sync_prefs.h"
-#include "components/sync/test/test_sync_service.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores;
-using password_manager::prefs::UseUpmLocalAndSeparateStoresState;
-using ::testing::ElementsAre;
-using ::testing::ElementsAreArray;
-using ::testing::Eq;
-using ::testing::Invoke;
-using ::testing::IsEmpty;
-using ::testing::Pointee;
-using ::testing::Return;
-using ::testing::UnorderedElementsAreArray;
-using ::testing::VariantWith;
-using ::testing::WithArg;
-
-namespace password_manager {
-
-namespace {
-
-constexpr base::TimeDelta kLatencyDelta = base::Milliseconds(123u);
-const PasswordStoreBackendError kBackendError =
-    PasswordStoreBackendError(PasswordStoreBackendErrorType::kUncategorized);
-
-const char kMigrationProgressStateHistogram[] =
-    "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-    "ProgressState";
-const char kMigrationLatencyHistogram[] =
-    "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.Latency";
-const char kMigrationSuccessHistogram[] =
-    "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.Success";
-
-PasswordForm CreateTestPasswordForm(int index = 0) {
-  PasswordForm form;
-  form.url = GURL("https://test" + base::NumberToString(index) + ".com");
-  form.signon_realm = form.url.spec();
-  form.username_value = u"username" + base::NumberToString16(index);
-  form.password_value = u"password" + base::NumberToString16(index);
-  form.in_store = PasswordForm::Store::kProfileStore;
-  return form;
-}
-
-}  // namespace
-
-// Checks that the migration is started only when all the conditions are
-// satisfied. It also check that migration result is properly recorded in prefs.
-class BuiltInBackendToAndroidBackendMigratorTest : public testing::Test {
- protected:
-  BuiltInBackendToAndroidBackendMigratorTest() = default;
-  ~BuiltInBackendToAndroidBackendMigratorTest() override = default;
-
-  void Init(int current_migration_version = 0) {
-    prefs_.registry()->RegisterIntegerPref(
-        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-    prefs_.SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                      current_migration_version);
-    prefs_.registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
-                                          0.0);
-    prefs_.registry()->RegisterStringPref(
-        ::prefs::kGoogleServicesLastSyncingUsername, "testaccount@gmail.com");
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kUnenrolledFromGoogleMobileServicesDueToErrors, false);
-    prefs_.registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kShouldShowPostPasswordMigrationSheetAtStartup, false);
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kEmptyProfileStoreLoginDatabase, false);
-    prefs_.registry()->RegisterBooleanPref(
-        syncer::prefs::internal::kSyncInitialSyncFeatureSetupComplete, false);
-    prefs_.registry()->RegisterBooleanPref(
-        syncer::prefs::internal::kSyncKeepEverythingSynced, false);
-    prefs_.registry()->RegisterBooleanPref(
-        base::StrCat(
-            {syncer::prefs::internal::
-                 kSyncDataTypeStatusForSyncToSigninMigrationPrefix,
-             ".", syncer::DataTypeToStableLowerCaseString(syncer::PASSWORDS)}),
-        false);
-    CreateMigrator(&built_in_backend_, &android_backend_, &prefs_);
-  }
-
-  void InitSyncService(bool is_password_sync_enabled) {
-    if (is_password_sync_enabled) {
-      sync_service_.GetUserSettings()->SetSelectedTypes(
-          /*sync_everything=*/false,
-          /*types=*/{syncer::UserSelectableType::kPasswords});
-    } else {
-      sync_service_.GetUserSettings()->SetSelectedTypes(
-          /*sync_everything=*/false, /*types=*/{});
-    }
-    migrator()->OnSyncServiceInitialized(&sync_service_);
-  }
-
-  // BuiltInBackendToAndroidBackendMigrator reads whether password sync is
-  // enabled from a pref rather than the SyncService. This helper sets such
-  // pref.
-  void SetPasswordSyncEnabledPref(bool enabled) {
-    if (enabled) {
-      prefs_.SetBoolean(
-          syncer::prefs::internal::kSyncInitialSyncFeatureSetupComplete, true);
-      prefs_.SetBoolean(syncer::prefs::internal::kSyncKeepEverythingSynced,
-                        true);
-      prefs_.SetBoolean(
-          base::StrCat(
-              {syncer::prefs::internal::
-                   kSyncDataTypeStatusForSyncToSigninMigrationPrefix,
-               ".",
-               syncer::DataTypeToStableLowerCaseString(syncer::PASSWORDS)}),
-          true);
-    } else {
-      prefs_.SetBoolean(
-          syncer::prefs::internal::kSyncInitialSyncFeatureSetupComplete, false);
-    }
-  }
-
-  void CreateMigrator(PasswordStoreBackend* built_in_backend,
-                      PasswordStoreBackend* android_backend,
-                      PrefService* prefs) {
-    migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
-        built_in_backend, android_backend, prefs);
-  }
-
-  PasswordStoreBackend& built_in_backend() { return built_in_backend_; }
-  PasswordStoreBackend& android_backend() { return android_backend_; }
-
-  TestingPrefServiceSimple* prefs() { return &prefs_; }
-  BuiltInBackendToAndroidBackendMigrator* migrator() { return migrator_.get(); }
-
-  void RunUntilIdle() { task_env_.RunUntilIdle(); }
-  void FastForwardBy(base::TimeDelta delta) { task_env_.FastForwardBy(delta); }
-
- private:
-  base::test::SingleThreadTaskEnvironment task_env_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  TestingPrefServiceSimple prefs_;
-  syncer::TestSyncService sync_service_;
-  FakePasswordStoreBackend built_in_backend_;
-  FakePasswordStoreBackend android_backend_{
-      IsAccountStore(false),
-      FakePasswordStoreBackend::UpdateAlwaysSucceeds(true)};
-  std::unique_ptr<BuiltInBackendToAndroidBackendMigrator> migrator_;
-};
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       CurrentMigrationVersionIsUpdatedWhenMigrationIsNeeded) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(1, prefs()->GetInteger(
-                   prefs::kCurrentMigrationVersionToGoogleMobileServices));
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       LocalPasswordMigrationRecordsProgressState) {
-  base::HistogramTester histogram_tester;
-  Init();
-
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  migrator()->StartMigrationOfLocalPasswords();
-  histogram_tester.ExpectBucketCount(
-      kMigrationProgressStateHistogram,
-      metrics_util::LocalPwdMigrationProgressState::kStarted, 1);
-
-  RunUntilIdle();
-  ASSERT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  histogram_tester.ExpectBucketCount(
-      kMigrationProgressStateHistogram,
-      metrics_util::LocalPwdMigrationProgressState::kFinished, 1);
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       AllPrefsAreUpdatedAfterLocalPasswordsMigration) {
-  Init();
-
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  migrator()->StartMigrationOfLocalPasswords();
-
-  RunUntilIdle();
-
-  EXPECT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-  EXPECT_TRUE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       AllPrefsAreUpdatedAfterOnlySettingsMigration) {
-  Init();
-
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-  prefs()->SetBoolean(password_manager::prefs::kEmptyProfileStoreLoginDatabase,
-                      true);
-
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-  EXPECT_FALSE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-// The user was syncing and got unenrolled, but then disabled sync and the
-// unenrollment pref wasn't reset.
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       PostMigrationSheetIsScheduledForLocalUnenrolledUsers) {
-  Init();
-  SetPasswordSyncEnabledPref(false);
-  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-                      true);
-
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-  EXPECT_TRUE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       PostMigrationSheetIsNotScheduledForUnenrolledUsers) {
-  Init();
-  SetPasswordSyncEnabledPref(true);
-  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-                      true);
-
-  InitSyncService(/*is_password_sync_enabled=*/true);
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-  EXPECT_FALSE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       PostMigrationSheetIsNotScheduledForNotMigratedUsers) {
-  Init();
-  SetPasswordSyncEnabledPref(true);
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-
-  InitSyncService(/*is_password_sync_enabled=*/true);
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-  EXPECT_FALSE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       AttemptPrefIsUpdatedAfterLocalMigrationStarted) {
-  Init();
-  ASSERT_EQ(
-      base::Time().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(
-      base::Time::Now().InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       PrefsUnchangedWhenAttemptedMigrationEarlierToday) {
-  Init();
-
-  prefs()->SetDouble(
-      password_manager::prefs::kTimeOfLastMigrationAttempt,
-      (base::Time::Now() - base::Hours(2)).InSecondsFSinceUnixEpoch());
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(0, prefs()->GetInteger(
-                   prefs::kCurrentMigrationVersionToGoogleMobileServices));
-  EXPECT_EQ(
-      (base::Time::Now() - base::Hours(2)).InSecondsFSinceUnixEpoch(),
-      prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       MigrationNeverStartedMetrics) {
-  base::HistogramTester histogram_tester;
-  const char kMigrationFinishedMetric[] =
-      "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
-  Init();
-
-  histogram_tester.ExpectTotalCount(kMigrationFinishedMetric, 1);
-  histogram_tester.ExpectBucketCount(kMigrationFinishedMetric, false, 1);
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest, MigrationFinishedMetrics) {
-  base::HistogramTester histogram_tester;
-  const char kMigrationFinishedMetric[] =
-      "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
-
-  Init(/*current_migration_version=*/1);
-
-  histogram_tester.ExpectUniqueSample(kMigrationFinishedMetric, true, 1);
-}
-
-// Tests that migration removes blocklisted entries with non-empty username or
-// values from the built in backlend before writing to the Android backend.
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       MigrationClearsBlocklistedCredentials) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  // Add two incorrect entries to the local database to check if they will be
-  // removed before writing to the android backend
-  PasswordForm form_1 = CreateTestPasswordForm(1);
-  form_1.blocked_by_user = true;
-  form_1.username_value.clear();
-  built_in_backend().AddLoginAsync(form_1, base::DoNothing());
-
-  PasswordForm form_2 = CreateTestPasswordForm(2);
-  form_2.blocked_by_user = true;
-  form_1.password_value.clear();
-  built_in_backend().AddLoginAsync(form_2, base::DoNothing());
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  // Credentials should be cleaned in both android and built in backends.
-  EXPECT_CALL(mock_reply, Run(VariantWith<LoginsResult>((IsEmpty())))).Times(2);
-  android_backend().GetAllLoginsAsync(mock_reply.Get());
-  built_in_backend().GetAllLoginsAsync(mock_reply.Get());
-  RunUntilIdle();
-
-  EXPECT_TRUE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-// Tests that migration does not affect username and password for
-// non-blocklisted entries.
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       MigrationDoesNotClearNonBlocklistedCredentials) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  // Add two incorrect entries to the local database to check if they will be
-  // fixed before writing to the android backend
-  PasswordForm form_1 = CreateTestPasswordForm(1);
-  built_in_backend().AddLoginAsync(form_1, base::DoNothing());
-
-  PasswordForm form_2 = CreateTestPasswordForm(2);
-  built_in_backend().AddLoginAsync(form_2, base::DoNothing());
-
-  // Add one form to be updated.
-  android_backend().AddLoginAsync(form_1, base::DoNothing());
-  RunUntilIdle();
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  // Credentials should be cleaned in both android and built in backends.
-  EXPECT_CALL(mock_reply,
-              Run(VariantWith<LoginsResult>(ElementsAre(form_1, form_2))))
-      .Times(2);
-  android_backend().GetAllLoginsAsync(mock_reply.Get());
-  built_in_backend().GetAllLoginsAsync(mock_reply.Get());
-  RunUntilIdle();
-
-  EXPECT_TRUE(prefs()->GetBoolean(
-      prefs::kShouldShowPostPasswordMigrationSheetAtStartup));
-}
-
-// The user was syncing and got unenrolled, but then disabled sync and the
-// unenrollment pref wasn't reset.
-TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
-       UnenrollmentPrefsAreResetOnLocalPasswordMigration) {
-  Init();
-  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-                      true);
-  prefs()->SetInteger(
-      kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending));
-
-  InitSyncService(/*is_password_sync_enabled=*/true);
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  EXPECT_EQ(static_cast<int>(UseUpmLocalAndSeparateStoresState::kOn),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-  EXPECT_FALSE(prefs()->GetBoolean(
-      prefs::kUnenrolledFromGoogleMobileServicesDueToErrors));
-}
-
-class BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends
-    : public BuiltInBackendToAndroidBackendMigratorTest {
- protected:
-  BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends() = default;
-  ~BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends() override =
-      default;
-
-  void Init(int current_migration_version = 0) {
-    BuiltInBackendToAndroidBackendMigratorTest::Init(current_migration_version);
-    CreateMigrator(&built_in_backend_, &android_backend_, prefs());
-  }
-
-  MockPasswordStoreBackend built_in_backend_;
-  MockPasswordStoreBackend android_backend_;
-};
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends,
-       RemoveBlocklistedReturnsWithErrorDoesntCrash) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  base::HistogramTester histogram_tester;
-
-  PasswordForm form = CreateTestPasswordForm(1);
-  form.blocked_by_user = true;
-  std::vector<PasswordForm> built_in_logins = {std::move(form)};
-  EXPECT_CALL(built_in_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(std::move(built_in_logins)));
-  // Set up `RemoveLoginAsync` to return an error.
-  EXPECT_CALL(built_in_backend_, RemoveLoginAsync)
-      .WillOnce(base::test::RunOnceCallback<2>(kBackendError));
-  migrator()->StartMigrationOfLocalPasswords();
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "BuiltInBackend.RemoveLogin.Success",
-      false, 1);
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends,
-       UpdateLoginMetricReportsSuccess) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  base::HistogramTester histogram_tester;
-
-  // Set up conflicting passwords in the 2 backends, with the built-in backend
-  // containing the most recently used.
-  PasswordForm older_form = CreateTestPasswordForm(0);
-  PasswordForm newer_form = older_form;
-  newer_form.date_last_used = newer_form.date_last_used + base::Days(1);
-  newer_form.password_value = u"different password";
-  EXPECT_CALL(built_in_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(std::vector{newer_form}));
-  EXPECT_CALL(android_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(std::vector{older_form}));
-  EXPECT_CALL(android_backend_, UpdateLoginAsync)
-      .WillOnce(base::test::RunOnceCallback<1>(PasswordChangesOrError()));
-  migrator()->StartMigrationOfLocalPasswords();
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "AndroidBackend."
-      "UpdateLogin.Success",
-      true, 1);
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends,
-       UpdateLoginMetricReportsFailure) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  base::HistogramTester histogram_tester;
-
-  // Set up conflicting passwords in the 2 backends, with the built-in backend
-  // containing the most recently used.
-  PasswordForm older_form = CreateTestPasswordForm(0);
-  PasswordForm newer_form = older_form;
-  newer_form.date_last_used = newer_form.date_last_used + base::Days(1);
-  newer_form.password_value = u"different password";
-  EXPECT_CALL(built_in_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(std::vector{newer_form}));
-  EXPECT_CALL(android_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(std::vector{older_form}));
-  EXPECT_CALL(android_backend_, UpdateLoginAsync)
-      .WillOnce(base::test::RunOnceCallback<1>(kBackendError));
-  migrator()->StartMigrationOfLocalPasswords();
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "AndroidBackend.UpdateLogin.Success",
-      false, 1);
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorTestWithMockedBackends,
-       RemoveLoginMetricReportsSuccess) {
-  Init();
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  base::HistogramTester histogram_tester;
-
-  PasswordForm form_1 = CreateTestPasswordForm(1);
-  form_1.blocked_by_user = true;
-  std::vector<PasswordForm> built_in_logins = {std::move(form_1)};
-  EXPECT_CALL(built_in_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(std::move(built_in_logins)));
-  EXPECT_CALL(built_in_backend_, RemoveLoginAsync)
-      .WillOnce(base::test::RunOnceCallback<2>(PasswordChangesOrError()));
-  migrator()->StartMigrationOfLocalPasswords();
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "BuiltInBackend.RemoveLogin.Success",
-      true, 1);
-}
-
-// Holds the built in and android backend's logins and the expected result after
-// the migration.
-struct MigrationParam {
-  struct Entry {
-    Entry(int index,
-          std::string password = "",
-          base::TimeDelta date_created = base::TimeDelta(),
-          base::TimeDelta date_last_used = base::TimeDelta(),
-          base::TimeDelta date_password_modified = base::TimeDelta())
-        : index(index),
-          password(password),
-          date_created(date_created),
-          date_last_used(date_last_used),
-          date_password_modified(date_password_modified) {}
-
-    PasswordForm ToPasswordForm() const {
-      PasswordForm form = CreateTestPasswordForm(index);
-      form.password_value = base::ASCIIToUTF16(password);
-      form.date_created = base::Time() + date_created;
-      form.date_last_used = base::Time() + date_last_used;
-      form.date_password_modified = base::Time() + date_password_modified;
-      return form;
-    }
-
-    int index;
-    std::string password;
-    base::TimeDelta date_created;
-    base::TimeDelta date_last_used;
-    base::TimeDelta date_password_modified;
-  };
-
-  std::vector<PasswordForm> GetBuiltInLogins() const {
-    return EntriesToPasswordForms(built_in_logins);
-  }
-
-  std::vector<PasswordForm> GetAndroidLogins() const {
-    return EntriesToPasswordForms(android_logins);
-  }
-
-  std::vector<PasswordForm> GetMergedLogins() const {
-    return EntriesToPasswordForms(merged_logins);
-  }
-
-  std::vector<PasswordForm> EntriesToPasswordForms(
-      const std::vector<Entry>& entries) const {
-    std::vector<PasswordForm> v;
-    std::ranges::transform(entries, std::back_inserter(v),
-                           &Entry::ToPasswordForm);
-    return v;
-  }
-
-  std::vector<Entry> built_in_logins;
-  std::vector<Entry> android_logins;
-  std::vector<Entry> merged_logins;
-
-  int updated_in_android_backend_credentials_count = 0;
-
-  // The local passwords migration uses a merge algorithm for credentials
-  // with the same primary key in both backends,but different passwords.
-  // The conflicts are resolved in favor or the most recently created/mdoified
-  // entry. The conflict is won by the android backend when the most
-  // recent credential is stored there.
-  int conflicts_won_by_android = 0;
-};
-
-// Tests that the migration actually works by comparing passwords in
-// built-in/android backend before and after migration.
-class BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams
-    : public BuiltInBackendToAndroidBackendMigratorTest,
-      public testing::WithParamInterface<MigrationParam> {};
-
-// Tests the migration result.
-TEST_P(BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams,
-       LocalPwdMigrationAfterEnrollingIntoTheExperiment) {
-  base::HistogramTester histogram_tester;
-  // Set current_migration_version to 0 to imitate a user enrolling into the
-  // experiment.
-  BuiltInBackendToAndroidBackendMigratorTest::Init(
-      /*current_migration_version=*/0);
-
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-
-  const MigrationParam& p = GetParam();
-
-  for (const auto& login : p.GetBuiltInLogins()) {
-    built_in_backend().AddLoginAsync(login, base::DoNothing());
-  }
-  for (const auto& login : p.GetAndroidLogins()) {
-    android_backend().AddLoginAsync(login, base::DoNothing());
-  }
-  RunUntilIdle();
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  EXPECT_CALL(
-      mock_reply,
-      Run(VariantWith<LoginsResult>(ElementsAreArray(p.GetMergedLogins()))));
-  android_backend().GetAllLoginsAsync(mock_reply.Get());
-  RunUntilIdle();
-
-  // After local passwords migration, the credentials in the built in backend
-  // should stay unchanged.
-  EXPECT_CALL(
-      mock_reply,
-      Run(VariantWith<LoginsResult>(ElementsAreArray(p.GetBuiltInLogins()))));
-  built_in_backend().GetAllLoginsAsync(mock_reply.Get());
-  RunUntilIdle();
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "MergeWhereAndroidHasMostRecent",
-      GetParam().conflicts_won_by_android, 1);
-}
-
-TEST_P(BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams,
-       LocalPasswordsMigrationMetrics) {
-  base::HistogramTester histogram_tester;
-  BuiltInBackendToAndroidBackendMigratorTest::Init(
-      /*current_migration_version=*/0);
-
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-
-  const MigrationParam& p = GetParam();
-  for (const auto& login : p.GetBuiltInLogins()) {
-    built_in_backend().AddLoginAsync(login, base::DoNothing());
-  }
-  for (const auto& login : p.GetAndroidLogins()) {
-    android_backend().AddLoginAsync(login, base::DoNothing());
-  }
-  RunUntilIdle();
-
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  int added_to_android_backend_count =
-      p.GetMergedLogins().size() - p.GetAndroidLogins().size();
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "AddLoginCount",
-      added_to_android_backend_count, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "UpdateLoginCount",
-      p.updated_in_android_backend_credentials_count, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "MigratedLoginsTotalCount",
-      p.updated_in_android_backend_credentials_count +
-          added_to_android_backend_count,
-      1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "AndroidBackend."
-      "AddLogin.Success",
-      true, added_to_android_backend_count);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "AndroidBackend."
-      "UpdateLogin.Success",
-      true, p.updated_in_android_backend_credentials_count);
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    BuiltInBackendToAndroidBackendMigratorTest,
-    BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams,
-    testing::Values(
-        MigrationParam{.built_in_logins = {},
-                       .android_logins = {},
-                       .merged_logins = {},
-                       .conflicts_won_by_android = 0},
-        MigrationParam{.built_in_logins = {{1}, {2}},
-                       .android_logins = {},
-                       .merged_logins = {{1}, {2}},
-                       .updated_in_android_backend_credentials_count = 0,
-                       .conflicts_won_by_android = 0},
-        MigrationParam{.built_in_logins = {},
-                       .android_logins = {{1}, {2}},
-                       .merged_logins = {{1}, {2}},
-                       .conflicts_won_by_android = 0},
-        MigrationParam{.built_in_logins = {{1}, {2}},
-                       .android_logins = {{3}},
-                       .merged_logins = {{1}, {2}, {3}},
-                       .conflicts_won_by_android = 0},
-        MigrationParam{.built_in_logins = {{1}, {2}, {3}},
-                       .android_logins = {{1}, {2}, {3}},
-                       .merged_logins = {{1}, {2}, {3}},
-                       .conflicts_won_by_android = 0},
-
-        MigrationParam{
-            .built_in_logins = {{1, "old_password", base::Days(1)}, {2}},
-            .android_logins = {{1, "new_password", base::Days(2)}, {3}},
-            .merged_logins = {{1, "new_password", base::Days(2)}, {2}, {3}},
-            .conflicts_won_by_android = 1},
-        MigrationParam{
-            .built_in_logins = {{1, "new_password", base::Days(2)}, {2}},
-            .android_logins = {{1, "old_password", base::Days(1)}, {3}},
-            .merged_logins = {{1, "new_password", base::Days(2)}, {2}, {3}},
-            .updated_in_android_backend_credentials_count = 1,
-            .conflicts_won_by_android = 0},
-        MigrationParam{.built_in_logins = {{1, "new_password",
-                                            /*date_created=*/base::Days(1),
-                                            /*date_last_used=*/base::Days(2)}},
-                       .android_logins = {{1, "old_password",
-                                           /*date_created=*/base::Days(1)}},
-                       .merged_logins = {{1, "new_password", base::Days(1),
-                                          /*date_last_used=*/base::Days(2)}},
-                       .updated_in_android_backend_credentials_count = 1,
-                       .conflicts_won_by_android = 0},
-        MigrationParam{
-            .built_in_logins = {{1, "old_password",
-                                 /*date_created=*/base::Days(1),
-                                 /*date_last_used=*/base::Days(2),
-                                 /*date_password_modified=*/base::Days(2)}},
-            .android_logins = {{1, "new_password",
-                                /*date_created=*/base::Days(1),
-                                /*date_last_used=*/base::Days(2),
-                                /*date_password_modified=*/base::Days(3)}},
-            .merged_logins = {{1, "new_password",
-                               /*date_created=*/base::Days(1),
-                               /*date_last_used=*/base::Days(2),
-                               /*date_password_modified=*/base::Days(3)}},
-            .conflicts_won_by_android = 1}));
-
-struct MigrationParamForMetrics {
-  // Whether migration has already happened.
-  bool migration_ran_before;
-  // Whether password sync is enabled in settings.
-  bool is_sync_enabled;
-  // Whether migration should complete successfully or not.
-  bool is_successful_migration;
-};
-
-class BuiltInBackendToAndroidBackendMigratorTestMetrics
-    : public BuiltInBackendToAndroidBackendMigratorTest,
-      public testing::WithParamInterface<MigrationParamForMetrics> {
- protected:
-  BuiltInBackendToAndroidBackendMigratorTestMetrics() {
-    prefs()->registry()->RegisterIntegerPref(
-        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-    prefs()->registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
-                                            0.0);
-    prefs()->registry()->RegisterStringPref(
-        ::prefs::kGoogleServicesLastSyncingUsername, "testaccount@gmail.com");
-    prefs()->registry()->RegisterBooleanPref(
-        prefs::kUnenrolledFromGoogleMobileServicesDueToErrors, false);
-    prefs()->registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-    prefs()->registry()->RegisterBooleanPref(
-        prefs::kEmptyProfileStoreLoginDatabase, false);
-    prefs()->registry()->RegisterBooleanPref(
-        prefs::kShouldShowPostPasswordMigrationSheetAtStartup, false);
-    prefs()->registry()->RegisterBooleanPref(
-        syncer::prefs::internal::kSyncInitialSyncFeatureSetupComplete, false);
-    prefs()->registry()->RegisterBooleanPref(
-        syncer::prefs::internal::kSyncKeepEverythingSynced, false);
-
-    if (GetParam().migration_ran_before) {
-      // Setup the pref to indicate that the migration has happened already.
-      prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                          1);
-    }
-
-    CreateMigrator(&built_in_backend_, &android_backend_, prefs());
-  }
-
-  ::testing::StrictMock<MockPasswordStoreBackend> built_in_backend_;
-  ::testing::StrictMock<MockPasswordStoreBackend> android_backend_;
-};
-
-TEST_P(BuiltInBackendToAndroidBackendMigratorTestMetrics,
-       MigrationMetricsTest) {
-  base::HistogramTester histogram_tester;
-
-  InitSyncService(/*is_password_sync_enabled=*/GetParam().is_sync_enabled);
-
-  auto test_migration_callback = [](LoginsOrErrorReply reply) -> void {
-    LoginsResultOrError result = GetParam().is_successful_migration
-                                     ? LoginsResultOrError(LoginsResult())
-                                     : LoginsResultOrError(kBackendError);
-    base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-        FROM_HERE, base::BindOnce(std::move(reply), std::move(result)),
-        kLatencyDelta);
-  };
-
-  EXPECT_CALL(built_in_backend_, GetAllLoginsAsync)
-      .WillOnce(WithArg<0>(Invoke(test_migration_callback)));
-  EXPECT_CALL(android_backend_, GetAllLoginsAsync)
-      .WillOnce(base::test::RunOnceCallback<0>(LoginsResult()));
-
-  migrator()->StartMigrationOfLocalPasswords();
-  FastForwardBy(kLatencyDelta);
-
-  histogram_tester.ExpectTotalCount(kMigrationLatencyHistogram, 1);
-  histogram_tester.ExpectTimeBucketCount(kMigrationLatencyHistogram,
-                                         kLatencyDelta, 1);
-  histogram_tester.ExpectUniqueSample(kMigrationSuccessHistogram,
-                                      GetParam().is_successful_migration, 1);
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    BuiltInBackendToAndroidBackendMigratorTest,
-    BuiltInBackendToAndroidBackendMigratorTestMetrics,
-    testing::Values(
-        // Successful migration.
-        MigrationParamForMetrics{.migration_ran_before = false,
-                                 .is_sync_enabled = false,
-                                 .is_successful_migration = true},
-        // Unsuccessful migration.
-        MigrationParamForMetrics{.migration_ran_before = false,
-                                 .is_sync_enabled = false,
-                                 .is_successful_migration = false},
-        // Sync user, migration should not run.
-        MigrationParamForMetrics{.migration_ran_before = false,
-                                 .is_sync_enabled = true,
-                                 .is_successful_migration = false},
-        // User who already went through the migration. It should not run again.
-        MigrationParamForMetrics{.migration_ran_before = true,
-                                 .is_sync_enabled = false,
-                                 .is_successful_migration = false}));
-
-class BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest
-    : public BuiltInBackendToAndroidBackendMigratorTest {
- protected:
-  BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest() {
-    prefs()->registry()->RegisterIntegerPref(
-        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-    prefs()->registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
-                                            0.0);
-    prefs()->registry()->RegisterStringPref(
-        ::prefs::kGoogleServicesLastSyncingUsername, "testaccount@gmail.com");
-    prefs()->registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-
-    CreateMigrator(&built_in_backend_, &android_backend_, prefs());
-  }
-
-  PasswordStoreBackend& built_in_backend() { return built_in_backend_; }
-
-  ::testing::NiceMock<MockPasswordStoreBackend> android_backend_;
-
- private:
-  FakePasswordStoreBackend built_in_backend_;
-};
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest,
-       DoesNotCompleteMigrationWhenWritingToAndroidBackendFails) {
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-
-  // Sync state doesn't affect this test, run it arbitrarily for non-sync'ing
-  // users.
-  InitSyncService(/*is_password_sync_enabled=*/false);
-
-  // Add two credentials to the built-in backend.
-  built_in_backend().AddLoginAsync(CreateTestPasswordForm(/*index=*/1),
-                                   base::DoNothing());
-  built_in_backend().AddLoginAsync(CreateTestPasswordForm(/*index=*/2),
-                                   base::DoNothing());
-
-  // Simulate an empty Android backend.
-  EXPECT_CALL(android_backend_, GetAllLoginsAsync)
-      .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
-        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-            FROM_HERE, base::BindOnce(std::move(reply), LoginsResult()));
-      })));
-
-  // Simulate an Android backend that fails to write.
-  ON_CALL(android_backend_, AddLoginAsync)
-      .WillByDefault(
-          WithArg<1>(Invoke([](PasswordChangesOrErrorReply callback) -> void {
-            base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                FROM_HERE, base::BindOnce(std::move(callback), kBackendError));
-          })));
-
-  // Once one AddLoginAsync() call fails, all consecutive ones will not be
-  // executed. Check that exactly one AddLoginAsync() is called.
-  EXPECT_CALL(android_backend_, AddLoginAsync).Times(1);
-
-  migrator()->StartMigrationOfLocalPasswords();
-
-  // Local migration should still be pending since it didn' t complete
-  // successfully.
-  EXPECT_EQ(static_cast<int>(
-                UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending),
-            prefs()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores));
-
-  RunUntilIdle();
-}
-
-TEST_F(BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest,
-       LocalPasswordsMigrationMetricsWithErrorDuringMigration) {
-  // Sets up the backends mocks in the way:
-  // - built in backend has 2 passwords;
-  // - android backend has no passwords;
-  // - android backend will return an error when trying to add a second built in
-  // password;
-  std::vector<PasswordForm> built_in_passwords = {CreateTestPasswordForm(0),
-                                                  CreateTestPasswordForm(1)};
-  for (PasswordForm& form : built_in_passwords) {
-    built_in_backend().AddLoginAsync(form, base::DoNothing());
-  }
-  RunUntilIdle();
-  ON_CALL(android_backend_, GetAllLoginsAsync)
-      .WillByDefault(WithArg<0>(Invoke([&](LoginsOrErrorReply reply) -> void {
-        base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-            FROM_HERE,
-            base::BindOnce(std::move(reply), std::vector<PasswordForm>()));
-      })));
-  ON_CALL(android_backend_, AddLoginAsync(built_in_passwords[1], testing::_))
-      .WillByDefault(
-          WithArg<1>(Invoke([&](PasswordChangesOrErrorReply reply) -> void {
-            base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                FROM_HERE,
-                base::BindOnce(std::move(reply), PasswordChangesOrError()));
-          })));
-  ON_CALL(android_backend_, AddLoginAsync(built_in_passwords[0], testing::_))
-      .WillByDefault(
-          WithArg<1>(Invoke([&](PasswordChangesOrErrorReply reply) -> void {
-            base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                FROM_HERE, base::BindOnce(std::move(reply), kBackendError));
-          })));
-
-  prefs()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-
-  base::HistogramTester histogram_tester;
-  migrator()->StartMigrationOfLocalPasswords();
-  RunUntilIdle();
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "AddLoginCount",
-      1, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "UpdateLoginCount",
-      0, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "MigratedLoginsTotalCount",
-      1, 1);
-}
-
-}  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/ConfirmationDialogHelper.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/ConfirmationDialogHelper.java
index b5757e9..f62b15c 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/ConfirmationDialogHelper.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/ConfirmationDialogHelper.java
@@ -55,13 +55,16 @@
      * Shows an dialog to confirm the deletion.
      *
      * @param title A {@link String} used as title.
-     * @param message A {@link String} used message body.
+     * @param message A {@link CharSequence} used message body.
      * @param confirmButtonText A {@link String} for confirmation button label.
      * @param confirmedCallback A callback to run when the dialog is accepted.
      * @param declinedCallback A callback to run when the dialog is declined.
      */
     public void showConfirmation(
-            String title, String message, String confirmButtonText, Runnable confirmedCallback) {
+            String title,
+            CharSequence message,
+            String confirmButtonText,
+            Runnable confirmedCallback) {
         showConfirmation(
                 title,
                 message,
@@ -74,14 +77,14 @@
      * Shows an dialog to confirm the deletion.
      *
      * @param title A {@link String} used as title.
-     * @param message A {@link String} used message body.
+     * @param message A {@link CharSequence} used message body.
      * @param confirmButtonText A {@link String} for confirmation button label.
      * @param confirmedCallback A callback to run when the dialog is accepted.
      * @param declinedCallback A callback to run when the dialog is declined.
      */
     public void showConfirmation(
             String title,
-            String message,
+            CharSequence message,
             String confirmButtonText,
             Runnable confirmedCallback,
             Runnable declinedCallback) {
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerUtilBridge.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerUtilBridge.java
index 6722938..f6f2008 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerUtilBridge.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerUtilBridge.java
@@ -13,7 +13,6 @@
 import org.chromium.base.PackageUtils;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningType;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.sync.SyncService;
 
@@ -91,15 +90,6 @@
         return PasswordManagerUtilBridgeJni.get().areMinUpmRequirementsMet();
     }
 
-    public static @PasswordAccessLossWarningType int getPasswordAccessLossWarningType(
-            PrefService prefService) {
-        // The warning should not be shown on builds without UPM.
-        if (!isInternalBackendPresent()) {
-            return PasswordAccessLossWarningType.NONE;
-        }
-        return PasswordManagerUtilBridgeJni.get().getPasswordAccessLossWarningType(prefService);
-    }
-
     @NativeMethods
     public interface Natives {
         boolean isPasswordManagerAvailable(
@@ -114,8 +104,5 @@
                 @JniType("syncer::SyncService*") @Nullable SyncService syncService);
 
         boolean areMinUpmRequirementsMet();
-
-        @PasswordAccessLossWarningType
-        int getPasswordAccessLossWarningType(@JniType("PrefService*") PrefService prefService);
     }
 }
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/ExportFlow.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/ExportFlow.java
index 80034d0..b3b5426 100644
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/ExportFlow.java
+++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/ExportFlow.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.password_manager.settings;
 
 import static org.chromium.build.NullUtil.assumeNonNull;
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.logExportFlowLastStepMetric;
 import static org.chromium.chrome.browser.password_manager.PasswordMetricsUtil.logPasswordsExportResult;
 
 import android.content.ActivityNotFoundException;
@@ -27,8 +26,6 @@
 import org.chromium.build.annotations.Initializer;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
-import org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningExportStep;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningType;
 import org.chromium.chrome.browser.password_manager.PasswordMetricsUtil;
 import org.chromium.chrome.browser.password_manager.PasswordMetricsUtil.HistogramExportResult;
 import org.chromium.chrome.browser.password_manager.R;
@@ -86,8 +83,6 @@
     /** Describes at which state the password export flow is. */
     @ExportState private int mExportState;
 
-    private final @PasswordAccessLossWarningType int mWarningType;
-
     /** Name of the subdirectory in cache which stores the exported passwords file. */
     private static final String PASSWORDS_CACHE_DIR = "/passwords";
 
@@ -162,11 +157,7 @@
 
     private boolean mPasswordSerializationStarted;
 
-    private boolean mExportFLowFinalStepLogged;
-
-    public ExportFlow(@PasswordAccessLossWarningType int warningType) {
-        mWarningType = warningType;
-    }
+    public ExportFlow() {}
 
     public String getExportEventHistogramName() {
         return mCallerMetricsId + ".Event";
@@ -235,8 +226,7 @@
                     R.string.password_settings_export_tips,
                     e.getMessage(),
                     getPositiveButtonLabelId(),
-                    HistogramExportResult.WRITE_FAILED,
-                    PasswordAccessLossWarningExportStep.SAVE_PWD_FILE_FAILED);
+                    HistogramExportResult.WRITE_FAILED);
             return;
         }
 
@@ -257,7 +247,6 @@
     public void startExporting() {
         assert mExportState == ExportState.INACTIVE;
         mPasswordSerializationStarted = false;
-        mExportFLowFinalStepLogged = false;
         // Disable re-triggering exporting until the current exporting finishes.
         mExportState = ExportState.REQUESTED;
 
@@ -282,8 +271,6 @@
                     .show();
             // Re-enable exporting, the current one was cancelled by Chrome.
             mExportState = ExportState.INACTIVE;
-            maybeLogExportFlowLastStepMetric(
-                    PasswordAccessLossWarningExportStep.NO_SCREEN_LOCK_SET_UP);
         } else {
             // Always trigger reauthentication at the start of the exporting flow, even if the last
             // one succeeded recently.
@@ -314,8 +301,7 @@
                             R.string.password_settings_export_tips,
                             errorMessage,
                             getPositiveButtonLabelId(),
-                            HistogramExportResult.WRITE_FAILED,
-                            PasswordAccessLossWarningExportStep.PWD_SERIALIZATION_FAILED);
+                            HistogramExportResult.WRITE_FAILED);
                 });
     }
 
@@ -389,8 +375,7 @@
             int descriptionId,
             @Nullable String detailedDescription,
             int positiveButtonLabelId,
-            @HistogramExportResult int histogramExportResult,
-            @PasswordAccessLossWarningExportStep int finalStep) {
+            @HistogramExportResult int histogramExportResult) {
         assert mErrorDialogParams == null;
         mDelegate.onExportFlowFailed();
         mProgressBarManager.hide(
@@ -401,7 +386,6 @@
                             positiveButtonLabelId,
                             histogramExportResult);
                 });
-        maybeLogExportFlowLastStepMetric(finalStep);
     }
 
     public void showExportErrorAndAbortImmediately(
@@ -506,8 +490,7 @@
                     R.string.password_settings_export_no_app,
                     e.getMessage(),
                     getPositiveButtonLabelId(),
-                    HistogramExportResult.NO_CONSUMER,
-                    PasswordAccessLossWarningExportStep.SAVE_PWD_FILE_FAILED);
+                    HistogramExportResult.NO_CONSUMER);
         }
     }
 
@@ -518,8 +501,7 @@
                     R.string.password_settings_export_tips,
                     "Could not create file.",
                     getPositiveButtonLabelId(),
-                    HistogramExportResult.WRITE_FAILED,
-                    PasswordAccessLossWarningExportStep.SAVE_PWD_FILE_FAILED);
+                    HistogramExportResult.WRITE_FAILED);
             return;
         }
         new AsyncTask<@Nullable String>() {
@@ -529,13 +511,6 @@
                 try {
                     writeToInternalStorage(mExportFileUri, passwordsFile);
                 } catch (IOException e) {
-                    // This metric should be logged in onPostExecute in case of an exception.
-                    // Since that happens in a callback, to be absolutely sure it's logged,
-                    // it's already logged here. It won't be logged as a duplicate because the
-                    // logging method checks if the metric was prevoiusly logged for the current
-                    // export flow.
-                    maybeLogExportFlowLastStepMetric(
-                            PasswordAccessLossWarningExportStep.SAVE_PWD_FILE_FAILED);
                     return e.getMessage();
                 }
                 return null;
@@ -550,8 +525,7 @@
                                         R.string.password_settings_export_tips,
                                         exceptionMessage,
                                         getPositiveButtonLabelId(),
-                                        HistogramExportResult.WRITE_FAILED,
-                                        PasswordAccessLossWarningExportStep.SAVE_PWD_FILE_FAILED);
+                                        HistogramExportResult.WRITE_FAILED);
                             } else {
                                 mDelegate.onExportFlowSucceeded();
                                 mExportFileUri = null;
@@ -591,8 +565,6 @@
                     ReauthenticationManager.ReauthScope.BULK)) {
                 exportAfterReauth();
             } else {
-                maybeLogExportFlowLastStepMetric(
-                        PasswordAccessLossWarningExportStep.AUTHENTICATION_EXPIRED);
                 mExportState = ExportState.INACTIVE;
             }
         }
@@ -621,27 +593,13 @@
     }
 
     private int getPositiveButtonLabelId() {
-        // Don't allow to try restarting the export flow from password access loss warning. The
-        // reason: it won't be able to create the file for saving passwords on disk because the
-        // dialog, which owns the export flow would be dismissed. There is a workaround: clicking on
-        // Google Password Manager will propose to restart the export flow.
+        // Don't allow to try restarting the export flow. The reason: it won't be able to create the
+        // file for saving passwords on disk because the dialog, which owns the export flow would be
+        // dismissed. There is a workaround: clicking on Google Password Manager will propose to
+        // restart the export flow.
         // TODO (crbug.com/364530583): returning 0 here means there should be only one "Close"
         // button in the dialog. Make error dialog configurable instead of passing a 0 resource into
         // it.
         return 0;
     }
-
-    private void maybeLogExportFlowLastStepMetric(
-            @PasswordAccessLossWarningExportStep int finalStep) {
-        // The serialization and reauthentication step might happen at the same time and might cause
-        // two final step metrics to be logged if they both fail. This method checks if the metric
-        // was already logged for this export flow before logging.
-        if (mExportFLowFinalStepLogged) {
-            return;
-        }
-        if (mWarningType != PasswordAccessLossWarningType.NONE) {
-            logExportFlowLastStepMetric(mWarningType, finalStep);
-        }
-        mExportFLowFinalStepLogged = true;
-    }
 }
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinator.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinator.java
deleted file mode 100644
index adf93d0..0000000
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinator.java
+++ /dev/null
@@ -1,136 +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.
-
-package org.chromium.chrome.browser.password_manager.settings;
-
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.logExportFlowLastStepMetric;
-
-import android.content.Context;
-import android.content.res.Resources;
-
-import org.chromium.base.supplier.Supplier;
-import org.chromium.build.annotations.NullMarked;
-import org.chromium.build.annotations.Nullable;
-import org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningExportStep;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningType;
-import org.chromium.chrome.browser.loading_modal.LoadingModalDialogCoordinator;
-import org.chromium.chrome.browser.password_manager.ManagePasswordsReferrer;
-import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
-import org.chromium.components.sync.SyncService;
-import org.chromium.ui.modaldialog.DialogDismissalCause;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modaldialog.ModalDialogProperties.ButtonType;
-import org.chromium.ui.modelutil.PropertyModel;
-
-import java.util.ArrayList;
-
-/**
- * Shows the dialog instructing the user to import their passwords into the GMS Core after they've
- * been saved to the file on disk. It is displayed only if the user has up to date GMS Core
- * installed. If user accepts, it redirects the user to Google Password Manager (GMS Core).
- */
-@NullMarked
-public class PasswordAccessLossImportDialogCoordinator {
-    private class ModalDialogController implements ModalDialogProperties.Controller {
-
-        @Override
-        public void onClick(PropertyModel model, int buttonType) {
-            if (buttonType == ButtonType.POSITIVE) {
-                // If password import is accepted, the GMS Core UI will be opened and the export
-                // flow in Chrome ends here.
-                logExportFlowLastStepMetric(
-                        PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED,
-                        PasswordAccessLossWarningExportStep.PASSWORD_IMPORT);
-                launchCredentialManager();
-                mChromeShutDownRunnable.run();
-            } else {
-                // If password import is rejected, then the export flow ends at this step.
-                logExportFlowLastStepMetric(
-                        PasswordAccessLossWarningType.NEW_GMS_CORE_MIGRATION_FAILED,
-                        PasswordAccessLossWarningExportStep.IMPORT_CANCELED);
-            }
-            mModalDialogManagerSupplier
-                    .get()
-                    .dismissDialog(
-                            model,
-                            buttonType == ButtonType.POSITIVE
-                                    ? DialogDismissalCause.POSITIVE_BUTTON_CLICKED
-                                    : DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
-        }
-
-        @Override
-        public void onDismiss(PropertyModel model, int dismissalCause) {
-            // This is called when the dialog is being dismissed and meant for cleanup. Nothing to
-            // clean up here.
-        }
-    }
-
-    private final Context mContext;
-    private final @Nullable SyncService mSyncService;
-    private final Supplier<ModalDialogManager> mModalDialogManagerSupplier;
-    private final PasswordManagerHelper mPasswordManagerHelper;
-    private final Runnable mChromeShutDownRunnable;
-
-    public PasswordAccessLossImportDialogCoordinator(
-            Context context,
-            @Nullable SyncService syncService,
-            Supplier<ModalDialogManager> modalDialogManagerSupplier,
-            PasswordManagerHelper passwordManagerHelper,
-            Runnable chromeShutDownRunnable) {
-        mContext = context;
-        mSyncService = syncService;
-        mModalDialogManagerSupplier = modalDialogManagerSupplier;
-        mPasswordManagerHelper = passwordManagerHelper;
-        mChromeShutDownRunnable = chromeShutDownRunnable;
-    }
-
-    public void showImportInstructionDialog() {
-        Resources resources = mContext.getResources();
-        ArrayList<CharSequence> messages = new ArrayList<>();
-        messages.add(
-                resources.getString(
-                        org.chromium.chrome.browser.password_manager.R.string
-                                .access_loss_import_dialog_desc));
-
-        PropertyModel model =
-                new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
-                        .with(ModalDialogProperties.CONTROLLER, new ModalDialogController())
-                        .with(
-                                ModalDialogProperties.TITLE,
-                                resources,
-                                org.chromium.chrome.browser.password_manager.R.string
-                                        .access_loss_import_dialog_title)
-                        .with(ModalDialogProperties.MESSAGE_PARAGRAPHS, messages)
-                        .with(
-                                ModalDialogProperties.POSITIVE_BUTTON_TEXT,
-                                resources,
-                                org.chromium.chrome.browser.password_manager.R.string
-                                        .access_loss_import_dialog_positive_button_text)
-                        .with(
-                                ModalDialogProperties.BUTTON_STYLES,
-                                ModalDialogProperties.ButtonStyles.PRIMARY_FILLED_NEGATIVE_OUTLINE)
-                        .with(
-                                ModalDialogProperties.NEGATIVE_BUTTON_TEXT,
-                                resources,
-                                org.chromium.chrome.browser.password_manager.R.string.cancel)
-                        .build();
-        mModalDialogManagerSupplier.get().showDialog(model, ModalDialogType.APP);
-    }
-
-    private void launchCredentialManager() {
-        // TODO (crbug.com/356851810): Add new referrer and replace CHROME_SETTINGS referrer with
-        // the new one.
-        LoadingModalDialogCoordinator loadingDialogCoordinator =
-                LoadingModalDialogCoordinator.create(mModalDialogManagerSupplier, mContext);
-        mPasswordManagerHelper.launchTheCredentialManager(
-                ManagePasswordsReferrer.ACCESS_LOSS_WARNING,
-                mSyncService,
-                loadingDialogCoordinator,
-                mModalDialogManagerSupplier,
-                mContext,
-                null);
-    }
-}
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinatorTest.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinatorTest.java
deleted file mode 100644
index 0e7e7c7f..0000000
--- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordAccessLossImportDialogCoordinatorTest.java
+++ /dev/null
@@ -1,149 +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.
-
-package org.chromium.chrome.browser.password_manager.settings;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import static org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.getExportFlowFinalStepHistogramName;
-
-import android.content.Context;
-import android.content.res.Resources;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.Robolectric;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.supplier.Supplier;
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.HistogramWatcher;
-import org.chromium.chrome.browser.access_loss.AccessLossWarningMetricsRecorder.PasswordAccessLossWarningExportStep;
-import org.chromium.chrome.browser.access_loss.PasswordAccessLossWarningType;
-import org.chromium.chrome.browser.password_manager.ManagePasswordsReferrer;
-import org.chromium.chrome.browser.password_manager.PasswordManagerHelper;
-import org.chromium.components.sync.SyncService;
-import org.chromium.ui.modaldialog.ModalDialogManager;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.test.util.modaldialog.FakeModalDialogManager;
-
-/** Tests for {@link PasswordAccessLossImportDialogCoordinator} */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-@Batch(Batch.PER_CLASS)
-public class PasswordAccessLossImportDialogCoordinatorTest {
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-    private PasswordAccessLossImportDialogCoordinator mCoordinator;
-    private Supplier<ModalDialogManager> mModalDialogManagerSupplier;
-    private FakeModalDialogManager mModalDialogManager;
-    private Context mContext;
-    @Mock private SyncService mSyncService;
-    @Mock private PasswordManagerHelper mPasswordManagerHelper;
-    @Mock private Runnable mChromeShutDownRunnable;
-
-    @Before
-    public void setUp() {
-        mModalDialogManager = new FakeModalDialogManager(ModalDialogManager.ModalDialogType.APP);
-        mModalDialogManagerSupplier = () -> mModalDialogManager;
-        mContext = RuntimeEnvironment.getApplication().getApplicationContext();
-        mCoordinator =
-                new PasswordAccessLossImportDialogCoordinator(
-                        mContext,
-                        mSyncService,
-                        mModalDialogManagerSupplier,
-                        mPasswordManagerHelper,
-                        mChromeShutDownRunnable);
-    }
-
-    @Test
-    public void testImportDialogStrings() {
-        mCoordinator.showImportInstructionDialog();
-
-        PropertyModel model = mModalDialogManager.getShownDialogModel();
-        Resources resources = RuntimeEnvironment.getApplication().getResources();
-        assertEquals(
-                resources.getString(
-                        org.chromium.chrome.browser.password_manager.R.string
-                                .access_loss_import_dialog_title),
-                model.get(ModalDialogProperties.TITLE));
-        assertEquals(
-                resources.getString(
-                        org.chromium.chrome.browser.password_manager.R.string
-                                .access_loss_import_dialog_desc),
-                model.get(ModalDialogProperties.MESSAGE_PARAGRAPHS).get(0));
-        assertEquals(1, model.get(ModalDialogProperties.MESSAGE_PARAGRAPHS).size());
-        assertEquals(
-                resources.getString(
-                        org.chromium.chrome.browser.password_manager.R.string
-                                .access_loss_import_dialog_positive_button_text),
-                model.get(ModalDialogProperties.POSITIVE_BUTTON_TEXT));
-        assertEquals(
-                resources.getString(org.chromium.chrome.browser.password_manager.R.string.cancel),
-                model.get(ModalDialogProperties.NEGATIVE_BUTTON_TEXT));
-    }
-
-    @Test
-    public void testImportDialogOpensCredentialManagerAndShutsDownChrome() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getExportFlowFinalStepHistogramName(
-                                        PasswordAccessLossWarningType
-                                                .NEW_GMS_CORE_MIGRATION_FAILED),
-                                PasswordAccessLossWarningExportStep.PASSWORD_IMPORT)
-                        .build();
-        mCoordinator.showImportInstructionDialog();
-        Robolectric.flushForegroundThreadScheduler();
-
-        mModalDialogManager.clickPositiveButton();
-
-        verify(mPasswordManagerHelper)
-                .launchTheCredentialManager(
-                        eq(ManagePasswordsReferrer.ACCESS_LOSS_WARNING),
-                        eq(mSyncService),
-                        any(),
-                        eq(mModalDialogManagerSupplier),
-                        eq(mContext),
-                        isNull());
-        verify(mChromeShutDownRunnable).run();
-        assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-
-    @Test
-    public void testCancelImportDialog() {
-        var histogram =
-                HistogramWatcher.newBuilder()
-                        .expectIntRecords(
-                                getExportFlowFinalStepHistogramName(
-                                        PasswordAccessLossWarningType
-                                                .NEW_GMS_CORE_MIGRATION_FAILED),
-                                PasswordAccessLossWarningExportStep.IMPORT_CANCELED)
-                        .build();
-        mCoordinator.showImportInstructionDialog();
-        Robolectric.flushForegroundThreadScheduler();
-
-        mModalDialogManager.clickNegativeButton();
-
-        verify(mPasswordManagerHelper, times(0))
-                .launchTheCredentialManager(anyInt(), any(), any(), any(), any(), any());
-        assertNull(mModalDialogManager.getShownDialogModel());
-        histogram.assertExpected();
-    }
-}
diff --git a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerCheckupHelperTest.java b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerCheckupHelperTest.java
index b1ed48c..2672b301 100644
--- a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerCheckupHelperTest.java
+++ b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerCheckupHelperTest.java
@@ -50,6 +50,7 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.HistogramWatcher;
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.loading_modal.LoadingModalDialogCoordinator;
 import org.chromium.chrome.browser.password_manager.CredentialManagerLauncher.CredentialManagerError;
 import org.chromium.chrome.browser.password_manager.PasswordCheckupClientHelper.PasswordCheckBackendException;
@@ -1195,11 +1196,7 @@
         PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest();
         assertNotNull(dialogModel);
         assertEquals(
-                testActivity
-                        .getResources()
-                        .getString(
-                                org.chromium.chrome.browser.access_loss.R.string
-                                        .pwm_disabled_no_gms_dialog_title),
+                testActivity.getResources().getString(R.string.pwm_disabled_no_gms_dialog_title),
                 dialogModel.get(ModalDialogProperties.TITLE));
     }
 
@@ -1224,11 +1221,7 @@
         PropertyModel dialogModel = mModalDialogManager.getCurrentDialogForTest();
         assertNotNull(dialogModel);
         assertEquals(
-                testActivity
-                        .getResources()
-                        .getString(
-                                org.chromium.chrome.browser.access_loss.R.string
-                                        .access_loss_update_gms_title),
+                testActivity.getResources().getString(R.string.access_loss_update_gms_title),
                 dialogModel.get(ModalDialogProperties.TITLE));
     }
 
diff --git a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
index a6ddc5b..b753d199 100644
--- a/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
+++ b/chrome/browser/password_manager/android/junit/src/org/chromium/chrome/browser/password_manager/PasswordManagerHelperTest.java
@@ -53,7 +53,6 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.HistogramWatcher;
-import org.chromium.chrome.browser.access_loss.R;
 import org.chromium.chrome.browser.loading_modal.LoadingModalDialogCoordinator;
 import org.chromium.chrome.browser.password_manager.CredentialManagerLauncher.CredentialManagerBackendException;
 import org.chromium.chrome.browser.password_manager.CredentialManagerLauncher.CredentialManagerError;
diff --git a/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.cc b/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.cc
deleted file mode 100644
index 06b0d74c..0000000
--- a/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.cc
+++ /dev/null
@@ -1,46 +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/password_manager/android/password_access_loss_warning_startup_launcher.h"
-
-#include <variant>
-
-#include "base/notreached.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_interface.h"
-
-PasswordAccessLossWarningStartupLauncher::
-    PasswordAccessLossWarningStartupLauncher(
-        ShowAccessLossWarningCallback show_access_loss_warning_callback)
-    : show_access_loss_warning_callback_(
-          std::move(show_access_loss_warning_callback)) {}
-
-PasswordAccessLossWarningStartupLauncher::
-    ~PasswordAccessLossWarningStartupLauncher() = default;
-
-void PasswordAccessLossWarningStartupLauncher::FetchPasswordsAndShowWarning(
-    password_manager::PasswordStoreInterface* store) {
-  store->GetAllLogins(weak_ptr_factory_.GetWeakPtr());
-}
-
-void PasswordAccessLossWarningStartupLauncher::
-    OnGetPasswordStoreResultsOrErrorFrom(
-        password_manager::PasswordStoreInterface* store,
-        password_manager::LoginsResultOrError results_or_error) {
-  if (std::holds_alternative<password_manager::PasswordStoreBackendError>(
-          results_or_error)) {
-    return;
-  }
-  password_manager::LoginsResult passwords =
-      std::move(std::get<password_manager::LoginsResult>(results_or_error));
-  if (passwords.empty()) {
-    return;
-  }
-  std::move(show_access_loss_warning_callback_).Run();
-}
-
-void PasswordAccessLossWarningStartupLauncher::OnGetPasswordStoreResults(
-    std::vector<std::unique_ptr<password_manager::PasswordForm>> results) {
-  NOTREACHED();
-}
diff --git a/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.h b/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.h
deleted file mode 100644
index 3c35575e..0000000
--- a/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_ACCESS_LOSS_WARNING_STARTUP_LAUNCHER_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_ACCESS_LOSS_WARNING_STARTUP_LAUNCHER_H_
-
-#include "base/memory/weak_ptr.h"
-#include "components/password_manager/core/browser/password_store/password_store_consumer.h"
-
-// Helper class used to launch the password access loss warning on startup.
-// It ensures that the warning is only shown if there are passwords saved in the
-// password store.
-class PasswordAccessLossWarningStartupLauncher
-    : public password_manager::PasswordStoreConsumer {
- public:
-  using ShowAccessLossWarningCallback = base::OnceCallback<void()>;
-  explicit PasswordAccessLossWarningStartupLauncher(
-      ShowAccessLossWarningCallback show_migration_warning_callback);
-
-  PasswordAccessLossWarningStartupLauncher(
-      const PasswordAccessLossWarningStartupLauncher&) = delete;
-  PasswordAccessLossWarningStartupLauncher& operator=(
-      const PasswordAccessLossWarningStartupLauncher&) = delete;
-
-  ~PasswordAccessLossWarningStartupLauncher() override;
-
-  // This fetches passwords from the store which is a first step in showing the
-  // warning.
-  void FetchPasswordsAndShowWarning(
-      password_manager::PasswordStoreInterface* store);
-
- private:
-  // Receives a result from the password store. If there are any saved passwords
-  // and all other conditions for showing the warning are met it will display
-  // it.
-  void OnGetPasswordStoreResultsOrErrorFrom(
-      password_manager::PasswordStoreInterface* store,
-      password_manager::LoginsResultOrError results_or_error) override;
-
-  // Not implemented. Required override.
-  void OnGetPasswordStoreResults(
-      std::vector<std::unique_ptr<password_manager::PasswordForm>>) override;
-
-  // Callback that will be invoked to trigger the warning UI. Used to facilitate
-  // testing.
-  ShowAccessLossWarningCallback show_access_loss_warning_callback_;
-
-  base::WeakPtrFactory<PasswordAccessLossWarningStartupLauncher>
-      weak_ptr_factory_{this};
-};
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_ACCESS_LOSS_WARNING_STARTUP_LAUNCHER_H_
diff --git a/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher_unittest.cc b/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher_unittest.cc
deleted file mode 100644
index c18a9536..0000000
--- a/chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher_unittest.cc
+++ /dev/null
@@ -1,99 +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/password_manager/android/password_access_loss_warning_startup_launcher.h"
-
-#include "base/memory/scoped_refptr.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "chrome/browser/password_manager/password_manager_test_util.h"
-#include "components/password_manager/core/browser/password_store/mock_password_store_interface.h"
-#include "components/password_manager/core/browser/password_store/password_store_interface.h"
-#include "components/password_manager/core/browser/password_store/test_password_store.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using password_manager::MockPasswordStoreInterface;
-using testing::_;
-
-namespace {
-password_manager::PasswordForm CreateTestPasswordForm() {
-  password_manager::PasswordForm form;
-  form.url = GURL("https://test.com");
-  form.signon_realm = form.url.spec();
-  form.username_value = u"username";
-  form.password_value = u"password";
-  return form;
-}
-
-password_manager::PasswordForm CreateTestBlocklistedPasswordForm() {
-  password_manager::PasswordForm form;
-  form.url = GURL("https://test.com");
-  form.signon_realm = form.url.spec();
-  form.blocked_by_user = true;
-  return form;
-}
-}  // namespace
-
-class PasswordAccessLossWarningStartupLauncherTest : public testing::Test {
- public:
-  PasswordAccessLossWarningStartupLauncherTest() {
-    store_->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
-    warning_startup_launcher_ =
-        std::make_unique<PasswordAccessLossWarningStartupLauncher>(
-            show_access_loss_warning_callback().Get());
-  }
-
-  ~PasswordAccessLossWarningStartupLauncherTest() override {
-    store_->ShutdownOnUIThread();
-  }
-
-  PasswordAccessLossWarningStartupLauncher* warning_startup_launcher() {
-    return warning_startup_launcher_.get();
-  }
-
-  base::MockCallback<
-      PasswordAccessLossWarningStartupLauncher::ShowAccessLossWarningCallback>&
-  show_access_loss_warning_callback() {
-    return show_access_loss_warning_callback_;
-  }
-
-  password_manager::PasswordStoreInterface* store() { return store_.get(); }
-
-  void RunUntilIdle() { task_environment_.RunUntilIdle(); }
-
- private:
-  base::test::SingleThreadTaskEnvironment task_environment_;
-  scoped_refptr<password_manager::TestPasswordStore> store_ =
-      base::MakeRefCounted<password_manager::TestPasswordStore>();
-  base::MockCallback<
-      PasswordAccessLossWarningStartupLauncher::ShowAccessLossWarningCallback>
-      show_access_loss_warning_callback_;
-  std::unique_ptr<PasswordAccessLossWarningStartupLauncher>
-      warning_startup_launcher_;
-};
-
-TEST_F(PasswordAccessLossWarningStartupLauncherTest,
-       DoesntTriggerWarningIfNoPasswords) {
-  EXPECT_CALL(show_access_loss_warning_callback(), Run).Times(0);
-  warning_startup_launcher()->FetchPasswordsAndShowWarning(store());
-  RunUntilIdle();
-}
-
-TEST_F(PasswordAccessLossWarningStartupLauncherTest,
-       TriggersWarningIfItHasPasswords) {
-  store()->AddLogin(CreateTestPasswordForm());
-  RunUntilIdle();
-  EXPECT_CALL(show_access_loss_warning_callback(), Run).Times(1);
-  warning_startup_launcher()->FetchPasswordsAndShowWarning(store());
-  RunUntilIdle();
-}
-
-TEST_F(PasswordAccessLossWarningStartupLauncherTest,
-       TriggersWarningIfItHasBlocklistedPasswords) {
-  store()->AddLogin(CreateTestBlocklistedPasswordForm());
-  RunUntilIdle();
-  EXPECT_CALL(show_access_loss_warning_callback(), Run).Times(1);
-  warning_startup_launcher()->FetchPasswordsAndShowWarning(store());
-  RunUntilIdle();
-}
diff --git a/chrome/browser/password_manager/android/password_manager_android_util.cc b/chrome/browser/password_manager/android/password_manager_android_util.cc
index f65446f..0fa39f40 100644
--- a/chrome/browser/password_manager/android/password_manager_android_util.cc
+++ b/chrome/browser/password_manager/android/password_manager_android_util.cc
@@ -7,7 +7,6 @@
 #include <string>
 
 #include "base/android/build_info.h"
-#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_functions.h"
@@ -17,15 +16,12 @@
 #include "chrome/browser/password_manager/android/password_manager_eviction_util.h"
 #include "chrome/browser/password_manager/android/password_manager_util_bridge.h"
 #include "chrome/browser/password_manager/android/password_manager_util_bridge_interface.h"
-#include "components/browser_sync/sync_to_signin_migration.h"
 #include "components/password_manager/core/browser/export/login_db_deprecation_password_exporter.h"
-#include "components/password_manager/core/browser/features/password_features.h"
 #include "components/password_manager/core/browser/password_manager_buildflags.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/password_sync_util.h"
 #include "components/password_manager/core/browser/split_stores_and_local_upm.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/pref_names.h"
@@ -43,29 +39,6 @@
 
 namespace {
 
-enum class UserType {
-  kSyncing,
-  kNonSyncingAndMigrationNeeded,
-  kNonSyncingAndNoMigrationNeeded,
-};
-
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused. Keep in sync with the corresponding
-// enum in tools/metrics/histograms/metadata/password/enums.xml.
-enum class ActivationError {
-  kNone = 0,
-  // (Deprecated) kUnenrolled = 1,
-  // (Deprecated) kInitialUpmMigrationMissing = 2,
-  // (Deprecated) kLoginDbFileMoveFailed = 3,
-  kOutdatedGmsCore = 4,
-  // (Deprecated) kFlagDisabled = 5,
-  // (Deprecated) kMigrationWarningUnacknowledged = 6,
-  kMaxValue = kOutdatedGmsCore,
-};
-
-// Set on startup before the local passwords migration starts.
-bool g_last_migration_attempt_failed = false;
-
 bool HasMinGmsVersionForFullUpmSupport() {
   std::string gms_version_str =
       base::android::BuildInfo::GetInstance()->gms_version_code();
@@ -76,141 +49,18 @@
          gms_version >= password_manager::GetLocalUpmMinGmsVersion();
 }
 
-bool IsPasswordSyncEnabled(PrefService* pref_service) {
-  // It's not possible to ask the SyncService whether password sync is enabled,
-  // the object wasn't created yet. Instead, that information is written to a
-  // pref during the previous execution and read now.
-  switch (browser_sync::GetSyncToSigninMigrationDataTypeDecision(
-      pref_service, syncer::PASSWORDS,
-      syncer::prefs::internal::kSyncPasswords)) {
-    // `kDontMigrateTypeNotActive` is handled same as if the data type was
-    // active, because all that matters is the user's choice to sync the type.
-    case browser_sync::SyncToSigninMigrationDataTypeDecision::
-        kDontMigrateTypeNotActive:
-    case browser_sync::SyncToSigninMigrationDataTypeDecision::kMigrate:
-      return true;
-    case browser_sync::SyncToSigninMigrationDataTypeDecision::
-        kDontMigrateTypeDisabled:
-      return false;
-  }
-}
-
-bool HasCustomPasswordSettings(PrefService* pref_service) {
-  bool has_custom_enable_service_setting =
-      !pref_service
-           ->FindPreference(password_manager::prefs::kCredentialsEnableService)
-           ->IsDefaultValue();
-  bool has_custom_auto_signin_setting =
-      !pref_service
-           ->FindPreference(
-               password_manager::prefs::kCredentialsEnableAutosignin)
-           ->IsDefaultValue();
-  return has_custom_enable_service_setting || has_custom_auto_signin_setting;
-}
-
-bool MustMigrateLocalPasswordsOrSettingsOnActivation(
-    PrefService* pref_service,
-    const base::FilePath& login_db_directory) {
-  CHECK(!IsPasswordSyncEnabled(pref_service));
-
-  // It's not possible to ask the (profile) PasswordStore whether it is empty,
-  // the object wasn't created yet. Instead, that information is written to the
-  // kEmptyProfileStoreLoginDatabase pref during the previous execution and read
-  // now. The pref is false by default, so a migration is required in doubt.
-  bool has_passwords_in_profile_login_db =
-      !pref_service->GetBoolean(
-          password_manager::prefs::kEmptyProfileStoreLoginDatabase) &&
-      base::PathExists(login_db_directory.Append(
-          password_manager::kLoginDataForProfileFileName));
-  return HasCustomPasswordSettings(pref_service) ||
-         has_passwords_in_profile_login_db;
-}
-
-UserType GetUserType(PrefService* pref_service,
-                     const base::FilePath& login_db_directory) {
-  if (IsPasswordSyncEnabled(pref_service)) {
-    return UserType::kSyncing;
-  }
-
-  return MustMigrateLocalPasswordsOrSettingsOnActivation(pref_service,
-                                                         login_db_directory)
-             ? UserType::kNonSyncingAndMigrationNeeded
-             : UserType::kNonSyncingAndNoMigrationNeeded;
-}
-
-void RecordActivationError(UserType user_type, ActivationError error) {
-  const char kHistogramPrefix[] = "PasswordManager.LocalUpmActivationError";
-  const char* suffix = nullptr;
-  switch (user_type) {
-    case UserType::kNonSyncingAndMigrationNeeded:
-      suffix = ".NonSyncingWithMigration";
-      break;
-    case UserType::kNonSyncingAndNoMigrationNeeded:
-      suffix = ".NonSyncingNoMigration";
-      break;
-    case UserType::kSyncing:
-      suffix = ".Syncing";
-      break;
-  }
-  CHECK(suffix);
-  base::UmaHistogramEnumeration(base::StrCat({kHistogramPrefix, suffix}),
-                                error);
-  base::UmaHistogramEnumeration(kHistogramPrefix, error);
-}
-
-// Must only be called if the state pref is kOff, to set it to kOn or
-// kOffAndMigrationPending if all the preconditions are satisfied.
-void MaybeActivateSplitStoresAndLocalUpm(
-    PrefService* pref_service,
-    const base::FilePath& login_db_directory) {
-  CHECK_EQ(GetSplitStoresAndLocalUpmPrefValue(pref_service), kOff);
-
-  UserType user_type = GetUserType(pref_service, login_db_directory);
-  if (!HasMinGmsVersionForFullUpmSupport()) {
-    RecordActivationError(user_type, ActivationError::kOutdatedGmsCore);
-    return;
-  }
-
-  UseUpmLocalAndSeparateStoresState state_to_set_on_success = kOn;
-  switch (user_type) {
-    case UserType::kNonSyncingAndNoMigrationNeeded:
-      break;
-    case UserType::kNonSyncingAndMigrationNeeded:
-      state_to_set_on_success = kOffAndMigrationPending;
-      break;
-    case UserType::kSyncing: {
-      // kCurrentMigrationVersionToGoogleMobileServices is only 0 or 1.
-      if (password_manager_upm_eviction::IsCurrentUserEvicted(pref_service) ||
-          pref_service->GetInteger(
-              kCurrentMigrationVersionToGoogleMobileServices) == 0) {
-        // Initial UPM was not activated properly. Attempt to migrate passwords
-        // to local GMSCore.
-        state_to_set_on_success = kOffAndMigrationPending;
-        break;
-      }
-      break;
-    }
-  }
-  RecordActivationError(user_type, ActivationError::kNone);
-  pref_service->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                           static_cast<int>(state_to_set_on_success));
-}
-
 #if !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
 // Called on startup to delete the login data files for users migrated to UPM
 // or for users who had all the unmigrated passwords auto-exported.
 // Must only be called if the value of the state pref
 // `PasswordsUseUPMLocalAndSeparateStores` is `On` and there
-// is no need for deactivation of local UPM or if
-// `features::kLoginDbDeprecationAndroid` is enabled and either UPM is already
-// active or unmigrated passwords have already been auto-exported.
+// is no need for deactivation of local UPM or either UPM is already active or
+// unmigrated passwords have already been auto-exported.
 void MaybeDeleteLoginDataFiles(PrefService* prefs,
                                const base::FilePath& login_db_directory) {
   bool already_active_in_upm =
       password_manager::UsesSplitStoresAndUPMForLocal(prefs);
   bool login_db_ready_for_deprecation =
-      base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid) &&
       LoginDbDeprecationReady(prefs);
   CHECK(already_active_in_upm || login_db_ready_for_deprecation);
 
@@ -263,98 +113,6 @@
 
 #endif  // !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
 
-// Must only be called if the state pref is kOn or kOffAndMigrationPending, to
-// set it to kOff if the user downgraded GmsCore. Any passwords saved to GmsCore
-// while in kOn will stay in GmsCore and become available again on the next
-// successful activation; they will not be migrated back to the LoginDB. If the
-// user is syncing, this function tries to undo [1] the Login DB file move done
-// in MaybeActivateSplitStoresAndLocalUpm() until crrev.com/c/6012360, and
-// aborts on failure [2].
-//
-// [1] In truth, this is only an "undo" if the user was already syncing *before*
-// the activation. In rare cases, they might have been signed out with saved
-// passwords, activated, enabled sync and now get deactivated. If so, this
-// function overwrites a non-empty profile Login DB. That's fine: the content
-// got migrated to GmsCore and will become available again on the next
-// successful activation.
-//
-// [2] In hindsight, this is questionable, because the user stays marked as
-// activated even though they can't use GmsCore APIs.
-void MaybeDeactivateSplitStoresAndLocalUpm(
-    PrefService* pref_service,
-    const base::FilePath& login_db_directory) {
-  CHECK_NE(GetSplitStoresAndLocalUpmPrefValue(pref_service), kOff);
-
-  // Continue recording the metric for previously activated users. so they show
-  // up on the dashboard no matter the aggregation window. One caveat is the
-  // state recorded now might not be the same one where the user got activated
-  // E.g. they might have gone from syncing to non-syncing. Also the recording
-  // here ignores the possibility that rollback fails due to base::ReplaceFile()
-  // below, but that should be negligible.
-  RecordActivationError(GetUserType(pref_service, login_db_directory),
-                        HasMinGmsVersionForFullUpmSupport()
-                            ? ActivationError::kNone
-                            : ActivationError::kOutdatedGmsCore);
-  if (HasMinGmsVersionForFullUpmSupport()) {
-#if !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
-    if (GetSplitStoresAndLocalUpmPrefValue(pref_service) == kOn) {
-      MaybeDeleteLoginDataFiles(pref_service, login_db_directory);
-    }
-#endif  // !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
-    // GmsCore was not downgraded, no need to deactivate.
-    return;
-  }
-
-  // GmsCore was downgraded, so from here on the function wants to deactivate.
-  base::FilePath profile_db_path =
-      login_db_directory.Append(password_manager::kLoginDataForProfileFileName);
-  base::FilePath account_db_path =
-      login_db_directory.Append(password_manager::kLoginDataForAccountFileName);
-  // Note: users who migrated after crrev.com/c/6012360 won't have an account
-  // login db to rename, but for those who do, keep this logic.
-  if (GetSplitStoresAndLocalUpmPrefValue(pref_service) == kOn &&
-      IsPasswordSyncEnabled(pref_service) &&
-      base::PathExists(account_db_path) &&
-      !base::ReplaceFile(account_db_path, profile_db_path, /*error=*/nullptr)) {
-    // See point [2] above.
-    return;
-  }
-
-  pref_service->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                           static_cast<int>(kOff));
-}
-
-std::string_view GetAccessLossWarningTypeName(
-    PasswordAccessLossWarningType warning_type) {
-  switch (warning_type) {
-    case PasswordAccessLossWarningType::kNoUpm:
-      return "NoUPM";
-    case PasswordAccessLossWarningType::kOnlyAccountUpm:
-      return "OnlyAccountUpm";
-    case PasswordAccessLossWarningType::kNoGmsCore:
-      return "NoGmsCore";
-    case PasswordAccessLossWarningType::kNewGmsCoreMigrationFailed:
-      return "NewGmsCoreMigrationFailed";
-    case PasswordAccessLossWarningType::kNone:
-      NOTREACHED();
-  }
-}
-
-void RecordPwmNotActiveReason(PasswordManagerNotAvailableReason reason) {
-  base::UmaHistogramEnumeration("PasswordManager.Android.NotAvailableReason",
-                                reason);
-}
-
-void RecordLocalUpmActivated(bool activated) {
-  base::UmaHistogramBoolean("PasswordManager.LocalUpmActivated", activated);
-}
-
-void RecordLocalUpmActivationStatus(
-    password_manager::prefs::UseUpmLocalAndSeparateStoresState upm_state) {
-  base::UmaHistogramEnumeration("PasswordManager.LocalUpmActivationStatus",
-                                upm_state);
-}
-
 PasswordManagerNotAvailableReason GetPasswordManagerNotActiveReason(
     PrefService* pref_service,
     PasswordManagerUtilBridgeInterface* util_bridge,
@@ -378,20 +136,16 @@
 void RecordLocalUpmActivationMetrics(
     PrefService* pref_service,
     PasswordManagerUtilBridgeInterface* util_bridge) {
-  // If the deprecation flag is not enabled these metrics are instead recorded
-  // directly in the activation algorithm.
-  CHECK(base::FeatureList::IsEnabled(
-      password_manager::features::kLoginDbDeprecationAndroid));
   bool is_internal_backend_present = util_bridge->IsInternalBackendPresent();
   bool is_pwm_available =
       IsPasswordManagerAvailable(pref_service, is_internal_backend_present);
-  RecordLocalUpmActivated(is_pwm_available);
-  RecordLocalUpmActivationStatus(is_pwm_available
-                                     ? UseUpmLocalAndSeparateStoresState::kOn
-                                     : UseUpmLocalAndSeparateStoresState::kOff);
+  base::UmaHistogramBoolean("PasswordManager.LocalUpmActivated",
+                            is_pwm_available);
   if (!is_pwm_available) {
-    RecordPwmNotActiveReason(GetPasswordManagerNotActiveReason(
-        pref_service, util_bridge, is_internal_backend_present));
+    base::UmaHistogramEnumeration(
+        "PasswordManager.Android.NotAvailableReason",
+        GetPasswordManagerNotActiveReason(pref_service, util_bridge,
+                                          is_internal_backend_present));
   }
 }
 
@@ -404,16 +158,6 @@
     return;
   }
 
-  if (!base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid)) {
-    // Reset the pref if the flag is off, to ensure that if a client switches
-    // from the "Enabled" to the "Disabled" group, they redo the export once
-    // the feature is eventually enabled for them.
-    prefs->SetBoolean(password_manager::prefs::kUpmUnmigratedPasswordsExported,
-                      false);
-    return;
-  }
-
   // If there are no passwords saved, there is nothing to export prior to
   // deprecation, so mark the export as done already.
   if (prefs->GetBoolean(
@@ -430,8 +174,6 @@
 bool IsPasswordManagerAvailable(
     const PrefService* prefs,
     std::unique_ptr<PasswordManagerUtilBridgeInterface> util_bridge) {
-  CHECK(base::FeatureList::IsEnabled(
-      password_manager::features::kLoginDbDeprecationAndroid));
   return IsPasswordManagerAvailable(prefs,
                                     util_bridge->IsInternalBackendPresent());
 }
@@ -455,8 +197,6 @@
 }
 
 bool LoginDbDeprecationReady(PrefService* prefs) {
-  CHECK(base::FeatureList::IsEnabled(
-      password_manager::features::kLoginDbDeprecationAndroid));
   bool upm_already_active =
       static_cast<UseUpmLocalAndSeparateStoresState>(prefs->GetInteger(
           password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores)) ==
@@ -520,100 +260,18 @@
   // without requiring another restart.
   password_manager_android_util::InitializeUpmUnmigratedPasswordsExportPref(
       pref_service, login_db_directory);
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid)) {
-    // If the login DB is being deprecated, only record metrics and do not
-    // perform the activation algorithm.
-    RecordLocalUpmActivationMetrics(pref_service, util_bridge.get());
+  // If the login DB is being deprecated, only record metrics and do not
+  // perform the activation algorithm.
+  RecordLocalUpmActivationMetrics(pref_service, util_bridge.get());
 #if !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
-    if (LoginDbDeprecationReady(pref_service)) {
-      MaybeDeleteLoginDataFiles(pref_service, login_db_directory);
-    }
-    if (pref_service->GetBoolean(
-            password_manager::prefs::kUpmAutoExportCsvNeedsDeletion)) {
-      DeleteAutoExportedCsv(pref_service, login_db_directory);
-    }
+  if (LoginDbDeprecationReady(pref_service)) {
+    MaybeDeleteLoginDataFiles(pref_service, login_db_directory);
+  }
+  if (pref_service->GetBoolean(
+          password_manager::prefs::kUpmAutoExportCsvNeedsDeletion)) {
+    DeleteAutoExportedCsv(pref_service, login_db_directory);
+  }
 #endif
-    return;
-  }
-
-  UseUpmLocalAndSeparateStoresState split_stores_and_local_upm =
-      GetSplitStoresAndLocalUpmPrefValue(pref_service);
-  g_last_migration_attempt_failed =
-      split_stores_and_local_upm == kOffAndMigrationPending ? true : false;
-  if (split_stores_and_local_upm != kOff) {
-    MaybeDeactivateSplitStoresAndLocalUpm(pref_service, login_db_directory);
-  } else {
-    MaybeActivateSplitStoresAndLocalUpm(pref_service, login_db_directory);
-  }
-
-  // Records false for users who had a migration scheduled but weren't activated
-  // yet, which is different from RecordActivationError().
-  RecordLocalUpmActivated(
-      password_manager::UsesSplitStoresAndUPMForLocal(pref_service));
-  RecordLocalUpmActivationStatus(
-      GetSplitStoresAndLocalUpmPrefValue(pref_service));
-}
-
-GmsVersionCohort GetGmsVersionCohort() {
-  std::string gms_version_str =
-      base::android::BuildInfo::GetInstance()->gms_version_code();
-  int gms_version = 0;
-  // GMSCore version could not be parsed, probably no GMSCore installed.
-  if (!base::StringToInt(gms_version_str, &gms_version)) {
-    return GmsVersionCohort::kNoGms;
-  }
-
-  // GMSCore version is pre-UPM.
-  if (gms_version < password_manager::kAccountUpmMinGmsVersion) {
-    return GmsVersionCohort::kNoUpmSupport;
-  }
-
-  // GMSCore version supports the account passwords, but doesn't support local
-  // passwords.
-  if (gms_version < password_manager::GetLocalUpmMinGmsVersion()) {
-    return GmsVersionCohort::kOnlyAccountUpmSupport;
-  }
-
-  return GmsVersionCohort::kFullUpmSupport;
-}
-
-bool LastMigrationAttemptToUpmLocalFailed() {
-  return g_last_migration_attempt_failed;
-}
-
-PasswordAccessLossWarningType GetPasswordAccessLossWarningType(
-    PrefService* pref_service) {
-  switch (GetGmsVersionCohort()) {
-    case GmsVersionCohort::kNoGms:
-      return PasswordAccessLossWarningType::kNoGmsCore;
-    case GmsVersionCohort::kNoUpmSupport:
-      return PasswordAccessLossWarningType::kNoUpm;
-    case GmsVersionCohort::kOnlyAccountUpmSupport:
-      return PasswordAccessLossWarningType::kOnlyAccountUpm;
-    case GmsVersionCohort::kFullUpmSupport: {
-      // GMSCore is up to date, but the local passwords migration has failed, so
-      // manual export/import flow should be done. Checking the
-      // `SplitStoresAndLocalUpmState` again here because the migration might
-      // have succeeded in this run.
-      if (g_last_migration_attempt_failed &&
-          GetSplitStoresAndLocalUpmPrefValue(pref_service) ==
-              kOffAndMigrationPending) {
-        return PasswordAccessLossWarningType::kNewGmsCoreMigrationFailed;
-      }
-      // Full support and the user is migrated, so no warning needs to be shown.
-      return PasswordAccessLossWarningType::kNone;
-    }
-  }
-}
-
-void RecordPasswordAccessLossWarningTriggerSource(
-    PasswordAccessLossWarningTriggers trigger_source,
-    PasswordAccessLossWarningType warning_type) {
-  base::UmaHistogramEnumeration(
-      base::StrCat({"PasswordManager.PasswordAccessLossWarningSheet",
-                    GetAccessLossWarningTypeName(warning_type), "Trigger"}),
-      trigger_source);
 }
 
 }  // namespace password_manager_android_util
diff --git a/chrome/browser/password_manager/android/password_manager_android_util.h b/chrome/browser/password_manager/android/password_manager_android_util.h
index 5e20583..1983f785 100644
--- a/chrome/browser/password_manager/android/password_manager_android_util.h
+++ b/chrome/browser/password_manager/android/password_manager_android_util.h
@@ -21,58 +21,6 @@
 
 namespace password_manager_android_util {
 
-// Represents different types of password access loss warning.
-//
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.access_loss
-//
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused. Always keep this enum in sync with the
-// corresponding PasswordAccessLossWarningTriggers in enums.xml.
-enum class PasswordAccessLossWarningType {
-  kNone = 0,       // No warning.
-  kNoGmsCore = 1,  // A warning that the password manager will stop working.
-  kNoUpm = 2,      // A warning that GMS Core is outdated; updated suggested.
-  kOnlyAccountUpm = 3,  // A warning that GMSCore is outdated; update suggested.
-  kNewGmsCoreMigrationFailed = 4,  // A warning for fixing the migration error.
-  kMaxValue = kNewGmsCoreMigrationFailed,
-};
-
-// All GMS version categories with regards to UPM support.
-enum class GmsVersionCohort {
-  kNoGms,
-  kNoUpmSupport,
-  kOnlyAccountUpmSupport,
-  kFullUpmSupport,
-};
-
-// Represents different causes for showing the password access loss warning.
-//
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused. Always keep this enum in sync with the
-// corresponding PasswordAccessLossWarningTriggers in enums.xml.
-enum class PasswordAccessLossWarningTriggers {
-  kChromeStartup = 0,
-  kPasswordSaveUpdateMessage = 1,
-  kTouchToFill = 2,
-  kKeyboardAcessorySheet = 3,
-  kKeyboardAcessoryBar = 4,
-  kAllPasswords = 5,
-  kMaxValue = kAllPasswords,
-};
-
-// Represents different actions that the user can take on the password access
-// loss warning.
-//
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused. Always keep this enum in sync with the
-// corresponding PasswordAccessLossWarningUserActions in enums.xml.
-enum class PasswordAccessLossWarningUserActions {
-  kMainAction = 0,
-  kHelpCenter = 1,
-  kDismissed = 2,
-  kMaxValue = kDismissed,
-};
-
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 //
@@ -148,35 +96,6 @@
     const base::FilePath& login_db_directory,
     std::unique_ptr<PasswordManagerUtilBridgeInterface> util_bridge);
 
-// Returns the GMS version type based on which kind of UPM support is possible
-// in that version.
-GmsVersionCohort GetGmsVersionCohort();
-
-// Returns whether the last attempt to migrate to UPM local failed.
-bool LastMigrationAttemptToUpmLocalFailed();
-
-// Checks which type of passwords access loss warning to show to the user if any
-// (`kNone` means that no warning will be displayed).
-// The order of the checks is the following:
-// - If GMS Core is not installed, `kNoGmsCore` is returned.
-// - If GMS Core is installed, but has no support for passwords (neither
-// account, nor local), `kNoUpm` is returned.
-// - If GMS Core is installed and has the version which supports account
-// passwords, but doesn't support local passwords, `kOnlyAccountUpm` is
-// returned.
-// - If there is a local passwords migration pending, then
-// `kNewGmsCoreMigrationFailed` is returned.
-// - Otherwise no warning should be shown so the function returens `kNone`.
-PasswordAccessLossWarningType GetPasswordAccessLossWarningType(
-    PrefService* pref_service);
-
-// Records the histogram that tracks when the password access loss warning was
-// shown.
-// TODO: crbug.com/369076084 - Clean-up when the warning UI is no longer used.
-void RecordPasswordAccessLossWarningTriggerSource(
-    PasswordAccessLossWarningTriggers trigger_source,
-    PasswordAccessLossWarningType warning_type);
-
 }  // namespace password_manager_android_util
 
 #endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_MANAGER_ANDROID_UTIL_H_
diff --git a/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc b/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc
index e5464ef..6f405ca7 100644
--- a/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc
+++ b/chrome/browser/password_manager/android/password_manager_android_util_unittest.cc
@@ -8,71 +8,26 @@
 #include <memory>
 
 #include "base/android/build_info.h"
-#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/functional/bind.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/run_loop.h"
-#include "base/scoped_observation.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/to_string.h"
-#include "base/task/bind_post_task.h"
-#include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/test_file_util.h"
 #include "build/build_config.h"
-#include "chrome/browser/password_manager/account_password_store_factory.h"
 #include "chrome/browser/password_manager/android/mock_password_manager_util_bridge.h"
-#include "chrome/browser/password_manager/profile_password_store_factory.h"
-#include "chrome/browser/prefs/browser_prefs.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
-#include "chrome/browser/sync/sync_service_factory.h"
-#include "chrome/browser/trusted_vault/trusted_vault_service_factory.h"
-#include "chrome/test/base/scoped_testing_local_state.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/browser_sync/sync_to_signin_migration.h"
-#include "components/keyed_service/core/service_access_type.h"
 #include "components/password_manager/core/browser/export/login_db_deprecation_password_exporter.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_form.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "components/password_manager/core/browser/password_store/fake_password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/login_database.h"
-#include "components/password_manager/core/browser/password_store/password_data_type_controller_delegate_android.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_built_in_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_interface.h"
-#include "components/password_manager/core/browser/password_store/password_store_results_observer.h"
-#include "components/password_manager/core/browser/password_store_factory_util.h"
 #include "components/password_manager/core/browser/split_stores_and_local_upm.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/pref_notifier_impl.h"
 #include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/prefs/testing_pref_store.h"
 #include "components/signin/public/base/consent_level.h"
-#include "components/sync/base/command_line_switches.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/base/pref_names.h"
-#include "components/sync/service/sync_prefs.h"
-#include "components/sync/service/sync_service.h"
-#include "components/sync/service/sync_service_impl.h"
-#include "components/sync/service/sync_user_settings.h"
-#include "components/sync/test/fake_server.h"
-#include "components/sync/test/fake_server_http_post_provider.h"
-#include "components/sync/test/fake_server_network_resources.h"
 #include "components/sync/test/test_sync_service.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -86,82 +41,11 @@
 using password_manager::prefs::UseUpmLocalAndSeparateStoresState::
     kOffAndMigrationPending;
 using password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn;
-using password_manager_android_util::GmsVersionCohort;
-using password_manager_android_util::PasswordAccessLossWarningType;
 using testing::Return;
 
 namespace password_manager_android_util {
 namespace {
 
-// Duplicated from password_manager_android_util.cc, which is fine since the
-// enum values should never change.
-enum class ActivationError {
-  kNone = 0,
-  kOutdatedGmsCore = 4,
-  kMax = kOutdatedGmsCore,
-};
-
-password_manager::PasswordForm MakeExampleForm() {
-  password_manager::PasswordForm form;
-  form.signon_realm = "https://g.com";
-  form.url = GURL(form.signon_realm);
-  form.username_value = u"username";
-  form.password_value = u"password";
-  return form;
-}
-
-class FakePasswordStoreAndroidBackend
-    : public password_manager::FakePasswordStoreBackend {
- public:
-  explicit FakePasswordStoreAndroidBackend(bool is_account_backend)
-      : is_account_backend_(is_account_backend) {}
-  ~FakePasswordStoreAndroidBackend() override = default;
-
-  std::unique_ptr<syncer::DataTypeControllerDelegate>
-  CreateSyncControllerDelegate() override {
-    if (!is_account_backend_) {
-      return nullptr;
-    }
-    return std::make_unique<
-        password_manager::PasswordDataTypeControllerDelegateAndroid>();
-  }
-
- private:
-  const bool is_account_backend_;
-};
-
-class SyncDataTypeActiveWaiter : public syncer::SyncServiceObserver {
- public:
-  SyncDataTypeActiveWaiter(syncer::SyncService* sync_service,
-                           syncer::DataType data_type)
-      : sync_service_(sync_service), data_type_(data_type) {}
-  SyncDataTypeActiveWaiter(const SyncDataTypeActiveWaiter&) = delete;
-  SyncDataTypeActiveWaiter& operator=(const SyncDataTypeActiveWaiter&) = delete;
-  ~SyncDataTypeActiveWaiter() override = default;
-
-  [[nodiscard]] bool Wait() {
-    observation_.Observe(sync_service_);
-    run_loop_.Run();
-    // OnStateChanged() resets `observation_` if successful.
-    return !observation_.IsObserving();
-  }
-
- private:
-  // syncer::SyncServiceObserver overrides.
-  void OnStateChanged(syncer::SyncService* service) override {
-    if (service->GetActiveDataTypes().Has(data_type_)) {
-      observation_.Reset();
-      run_loop_.Quit();
-    }
-  }
-
-  const raw_ptr<syncer::SyncService> sync_service_;
-  const syncer::DataType data_type_;
-  base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver>
-      observation_{this};
-  base::RunLoop run_loop_;
-};
-
 class PasswordManagerAndroidUtilTest : public testing::Test {
  public:
   PasswordManagerAndroidUtilTest() {
@@ -191,8 +75,6 @@
              ".", syncer::DataTypeToStableLowerCaseString(syncer::PASSWORDS)}),
         false);
     pref_service_.registry()->RegisterBooleanPref(
-        password_manager::prefs::kSettingsMigratedToUPMLocal, false);
-    pref_service_.registry()->RegisterBooleanPref(
         password_manager::prefs::kUpmUnmigratedPasswordsExported, false);
     pref_service_.registry()->RegisterBooleanPref(
         password_manager::prefs::kUpmAutoExportCsvNeedsDeletion, false);
@@ -355,8 +237,6 @@
 
 TEST_F(PasswordManagerAndroidUtilTest,
        PasswordManagerNotAvailableNoInternalBackend) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   // Make sure all the other criteria are fulfilled.
   base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
       base::NumberToString(GetLocalUpmMinGmsVersion()));
@@ -374,9 +254,6 @@
 
 TEST_F(PasswordManagerAndroidUtilTest,
        PasswordManagerNotAvailableGmsVersionTooLow) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
-
   std::unique_ptr<MockPasswordManagerUtilBridge> mock_util_bridge =
       std::make_unique<MockPasswordManagerUtilBridge>();
   EXPECT_CALL(*mock_util_bridge, IsInternalBackendPresent)
@@ -395,8 +272,6 @@
 
 TEST_F(PasswordManagerAndroidUtilTest,
        PasswordManagerNotAvailablePasswordsUnmigratedPasswords) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   std::unique_ptr<MockPasswordManagerUtilBridge> mock_util_bridge =
       std::make_unique<MockPasswordManagerUtilBridge>();
   EXPECT_CALL(*mock_util_bridge, IsInternalBackendPresent)
@@ -414,8 +289,6 @@
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, PasswordManagerAvailableNoUpmMigration) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   std::unique_ptr<MockPasswordManagerUtilBridge> mock_util_bridge =
       std::make_unique<MockPasswordManagerUtilBridge>();
   EXPECT_CALL(*mock_util_bridge, IsInternalBackendPresent)
@@ -433,8 +306,6 @@
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, PasswordManagerAvailableUpmMigration) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   std::unique_ptr<MockPasswordManagerUtilBridge> mock_util_bridge =
       std::make_unique<MockPasswordManagerUtilBridge>();
   EXPECT_CALL(*mock_util_bridge, IsInternalBackendPresent)
@@ -452,8 +323,6 @@
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, TestRecordsUpmNotActiveWhenNoGms) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
       base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
 
@@ -467,15 +336,11 @@
   histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
                                       false, 1);
   histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-  histogram_tester.ExpectUniqueSample(
       "PasswordManager.Android.NotAvailableReason",
       PasswordManagerNotAvailableReason::kNoGmsCore, 1);
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, TestRecordsUpmNotActiveWhenGmsTooOld) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
       base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
 
@@ -489,16 +354,12 @@
   histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
                                       false, 1);
   histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-  histogram_tester.ExpectUniqueSample(
       "PasswordManager.Android.NotAvailableReason",
       PasswordManagerNotAvailableReason::kOutdatedGmsCore, 1);
 }
 
 TEST_F(PasswordManagerAndroidUtilTest,
        TestRecordsUpmNotActivateBeforeAutoExport) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
       base::NumberToString(GetLocalUpmMinGmsVersion()));
 
@@ -513,15 +374,11 @@
   histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
                                       false, 1);
   histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-  histogram_tester.ExpectUniqueSample(
       "PasswordManager.Android.NotAvailableReason",
       PasswordManagerNotAvailableReason::kAutoExportPending, 1);
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, TestRecordsUpmActiveIfExported) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
       base::NumberToString(GetLocalUpmMinGmsVersion()));
 
@@ -535,15 +392,11 @@
                                    GetMockBridgeWithBackendPresent());
   histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated", true,
                                       1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
   histogram_tester.ExpectTotalCount(
       "PasswordManager.Android.NotAvailableReason", 0);
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, TestRecordsUpmActiveIfAlreadyActive) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
       base::NumberToString(GetLocalUpmMinGmsVersion()));
 
@@ -557,16 +410,12 @@
                                    GetMockBridgeWithBackendPresent());
   histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated", true,
                                       1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
   histogram_tester.ExpectTotalCount(
       "PasswordManager.Android.NotAvailableReason", 0);
 }
 
 TEST_F(PasswordManagerAndroidUtilTest,
        InitUnmigratedExportUnchangedIfMigrated) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   pref_service()->SetInteger(
       password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
       static_cast<int>(
@@ -580,8 +429,6 @@
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, InitUnmigratedExportPrefTrueEmptyDb) {
-  base::test::ScopedFeatureList feature_list{
-      password_manager::features::kLoginDbDeprecationAndroid};
   pref_service()->SetInteger(
       password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
       static_cast<int>(
@@ -596,29 +443,8 @@
       password_manager::prefs::kUpmUnmigratedPasswordsExported));
 }
 
-TEST_F(PasswordManagerAndroidUtilTest, InitUnmigratedExportPrefFalseFlagOff) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
-  pref_service()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUpmUnmigratedPasswordsExported, true);
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kUpmUnmigratedPasswordsExported));
-}
-
 TEST_F(PasswordManagerAndroidUtilTest,
        DeletesLoginDataFilesAfterUnmigratedPasswordsExported) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
   base::HistogramTester histogram_tester;
   const char kRemovalStatusProfileMetric[] =
       "PasswordManager.ProfileLoginData.RemovalStatus";
@@ -673,9 +499,6 @@
 // This test is relevant for users for whom prior db deletion attempts failed.
 TEST_F(PasswordManagerAndroidUtilTest,
        DeletesLoginDataFilesForAlreadyMigratedUser) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
   base::HistogramTester histogram_tester;
   const char kRemovalStatusProfileMetric[] =
       "PasswordManager.ProfileLoginData.RemovalStatus";
@@ -727,9 +550,6 @@
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, DeletesExportedCsvIfNeeded) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
   base::HistogramTester histogram_tester;
   // Signal that the file needs deleting. This would happen if the original
   // deletion attempt failed.
@@ -754,9 +574,6 @@
 }
 
 TEST_F(PasswordManagerAndroidUtilTest, DoesntDeleteExportedCsvIfNotNeeded) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      password_manager::features::kLoginDbDeprecationAndroid);
   base::HistogramTester histogram_tester;
 
   pref_service()->SetBoolean(kUpmAutoExportCsvNeedsDeletion, false);
@@ -779,1137 +596,5 @@
       "PasswordManager.UPM.AutoExportedCsvStartupDeletionSuccess", 0);
 }
 
-// Unit tests for the activation algorithm. No longer relevant after the login
-// db deprecation.
-class PasswordManagerUpmActivationTest : public PasswordManagerAndroidUtilTest {
- public:
-  PasswordManagerUpmActivationTest() {
-    feature_list_.InitAndDisableFeature(
-        password_manager::features::kLoginDbDeprecationAndroid);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_F(
-    PasswordManagerUpmActivationTest,
-    SetUsesSplitStoresAndUPMForLocal_SignedOutWithNoPasswordsAndDefaultSettings) {
-  auto histogram_tester = std::make_unique<base::HistogramTester>();
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, true);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The user got activated.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingNoMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       true, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
-  histogram_tester = std::make_unique<base::HistogramTester>();
-
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // After activation, next calls are no-ops, even if settings are customized.
-  // The histogram is now recorded for NonSyncingWithMigration though, which is
-  // a bit misleading.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       true, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_SignedOutNoPasswordsAndCustomSettings) {
-  auto histogram_tester = std::make_unique<base::HistogramTester>();
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, true);
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The migration is pending.
-  // The migration should happen because there are no local passwords. Only
-  // settings should be migrated.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOffAndMigrationPending));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       false, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOffAndMigrationPending, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_SignedOutWithFreshProfile) {
-  base::HistogramTester histogram_tester;
-  // kEmptyProfileStoreLoginDatabase is false, so in principle there would be
-  // local passwords to migrate. But actually the pref is just in its default
-  // state. This is a fresh profile without a DB file.
-  base::DeleteFile(login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName));
-  const PrefService::Preference* no_passwords_pref =
-      pref_service()->FindPreference(
-          password_manager::prefs::kEmptyProfileStoreLoginDatabase);
-  ASSERT_TRUE(no_passwords_pref->IsDefaultValue());
-  ASSERT_EQ(no_passwords_pref->GetValue()->GetBool(), false);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // User got activated.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingNoMigration",
-      ActivationError::kNone, 1);
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated", true,
-                                      1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_SignedOutWithPasswords) {
-  auto histogram_tester = std::make_unique<base::HistogramTester>();
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The migration got marked as pending (but the user is not considered
-  // activated).
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOffAndMigrationPending));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       false, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOffAndMigrationPending, 1);
-  histogram_tester = std::make_unique<base::HistogramTester>();
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The first migration didn't finish/succeed, so a new migration is scheduled.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOffAndMigrationPending));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       false, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOffAndMigrationPending, 1);
-  histogram_tester = std::make_unique<base::HistogramTester>();
-
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOn));
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The migration finished successfully, the user is activated, so next calls
-  // are no-ops.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       true, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
-}
-
-TEST_F(
-    PasswordManagerUpmActivationTest,
-    SetUsesSplitStoresAndUPMForLocal_SignedOutWithCustomEnableServiceSetting) {
-  auto histogram_tester = std::make_unique<base::HistogramTester>();
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The migration got marked as pending (but the user is not considered
-  // activated yet).
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOffAndMigrationPending));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       false, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOffAndMigrationPending, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_SignedOutWithCustomAutoSigninSetting) {
-  auto histogram_tester = std::make_unique<base::HistogramTester>();
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The migration got marked as pending (but the user is not considered
-  // activated yet).
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOffAndMigrationPending));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kNone, 1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       false, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOffAndMigrationPending, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_KeepMigrationPendingIfSyncEnabled) {
-  // Set up a user who was signed out with saved passwords (thus got into
-  // kOffAndMigrationPending), failed to migrate (thus stayed in
-  // kOffAndMigrationPending) and later enabled sync.
-  // kLoginDataForAccountFileName exists because the account store was created
-  // when the migration got scheduled, even if it was never used.
-  base::HistogramTester histogram_tester;
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOffAndMigrationPending));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-  SetPasswordSyncEnabledPref(true);
-  base::WriteFile(login_db_directory().Append(
-                      password_manager::kLoginDataForAccountFileName),
-                  "");
-  ASSERT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName)));
-  ASSERT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName)));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The browser should keep trying to migrate existing passwords to the *local*
-  // Android backend. The login database files should be untouched.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOffAndMigrationPending));
-  EXPECT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName)));
-  EXPECT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName)));
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOffAndMigrationPending, 1);
-
-  // Advanced case: deactivate too, by downgrading Gmscore.
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // kOn syncing users that get rolled back will "undo" the login DB file move,
-  // i.e. they replace the "profile" loginDB with the "account" one. This isn't
-  // always perfect, see comment MaybeDeactivateSplitStoresAndLocalUpm(). The
-  // "account" DB might even be empty and overwrite a non-empty "profile" one.
-  // However: for kOffAndMigrationPending users, the "account" DB is *surely*
-  // empty (password sync is suppressed). So replacing the file can only be
-  // worse. Instead, the DB files should just be untouched. The account one is
-  // empty anyway, so no data is leftover.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-  EXPECT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName)));
-  EXPECT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName)));
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                      false, 2);
-  histogram_tester.ExpectBucketCount("PasswordManager.LocalUpmActivationStatus",
-                                     kOff, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_SyncingHealthy) {
-  auto histogram_tester = std::make_unique<base::HistogramTester>();
-  SetPasswordSyncEnabledPref(true);
-  pref_service()->SetInteger(
-      password_manager::prefs::kCurrentMigrationVersionToGoogleMobileServices,
-      1);
-  // Custom password manager settings should not matter for syncing users.
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  ASSERT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-  ASSERT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName)));
-  ASSERT_FALSE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName)));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The user should've been activated.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  // The profile DB is no longer renamed following crrev.com/c/6012360 (no
-  // fallback needed anymore) and will be anyway deleted on the next startup.
-  EXPECT_TRUE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName)));
-  EXPECT_FALSE(base::PathExists(login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName)));
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.Syncing", ActivationError::kNone,
-      1);
-  histogram_tester->ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                       true, 1);
-  histogram_tester->ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_StaysActivatedIfEnabledSyncLater) {
-  // Set up a user that got activated while being signed out and later enabled
-  // sync, but didn't have kCurrentMigrationVersionToGoogleMobileServices set
-  // (that pref is part of a migration logic that's no longer triggered when
-  // the local UPM is activated).
-  base::HistogramTester histogram_tester;
-  SetPasswordSyncEnabledPref(true);
-  ASSERT_EQ(pref_service()->GetInteger(
-                password_manager::prefs::
-                    kCurrentMigrationVersionToGoogleMobileServices),
-            0);
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOn));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The histogram records for "Syncing", which is a bit misleading.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.Syncing", ActivationError::kNone,
-      1);
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated", true,
-                                      1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOn, 1);
-}
-
-TEST_F(
-    PasswordManagerUpmActivationTest,
-    SetUsesSplitStoresAndUPMForLocal_OldGmsNotActivatedIfSignedOutWithoutPasswords) {
-  base::HistogramTester histogram_tester;
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, true);
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingNoMigration",
-      ActivationError::kOutdatedGmsCore, 1);
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-}
-
-TEST_F(
-    PasswordManagerUpmActivationTest,
-    SetUsesSplitStoresAndUPMForLocal_OldGmsNotActivatedIfSignedOutWithPasswords) {
-  base::HistogramTester histogram_tester;
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingWithMigration",
-      ActivationError::kOutdatedGmsCore, 1);
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_OldGmsNotActivatedIfSyncing) {
-  base::HistogramTester histogram_tester;
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-  SetPasswordSyncEnabledPref(true);
-  pref_service()->SetInteger(
-      password_manager::prefs::kCurrentMigrationVersionToGoogleMobileServices,
-      1);
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.Syncing",
-      ActivationError::kOutdatedGmsCore, 1);
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_DowngradingGmsCoreDeactivates) {
-  base::HistogramTester histogram_tester;
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOn));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, true);
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationError.NonSyncingNoMigration",
-      ActivationError::kOutdatedGmsCore, 1);
-  histogram_tester.ExpectUniqueSample("PasswordManager.LocalUpmActivated",
-                                      false, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.LocalUpmActivationStatus", kOff, 1);
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_DowngradingGmsCoreCancelsMigration) {
-  // In the past the migration got scheduled, but never finished. GmsCore has
-  // since been downgraded.
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOffAndMigrationPending));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // Migration should have been canceled.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-}
-
-TEST_F(PasswordManagerUpmActivationTest,
-       SetUsesSplitStoresAndUPMForLocal_DeletesLoginDataFilesForMigratedUsers) {
-  base::HistogramTester histogram_tester;
-  const char kRemovalStatusProfileMetric[] =
-      "PasswordManager.ProfileLoginData.RemovalStatus";
-  const char kRemovalStatusAccountMetric[] =
-      "PasswordManager.AccountLoginData.RemovalStatus";
-
-  // This is a state of a local user that has just been migrated.
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOn));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-
-  // Creating the login data files for testing.
-  base::FilePath profile_db_path = login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName);
-  base::FilePath account_db_path = login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName);
-  base::FilePath profile_db_journal_path = login_db_directory().Append(
-      password_manager::kLoginDataJournalForProfileFileName);
-  base::FilePath account_db_journal_path = login_db_directory().Append(
-      password_manager::kLoginDataJournalForAccountFileName);
-
-  base::WriteFile(profile_db_path, "Test content");
-  base::WriteFile(account_db_path, "Test content");
-  base::WriteFile(profile_db_journal_path, "Test content");
-  base::WriteFile(account_db_journal_path, "Test content");
-
-  EXPECT_TRUE(PathExists(profile_db_path));
-  EXPECT_TRUE(PathExists(account_db_path));
-  EXPECT_TRUE(PathExists(profile_db_journal_path));
-  EXPECT_TRUE(PathExists(account_db_journal_path));
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The user wasn't deactivated, so the login data file should have been
-  // cleared because the user was already migrated to UPM with split stores.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOn));
-  EXPECT_FALSE(PathExists(profile_db_path));
-  EXPECT_FALSE(PathExists(account_db_path));
-  EXPECT_FALSE(PathExists(profile_db_journal_path));
-  EXPECT_FALSE(PathExists(account_db_journal_path));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase));
-
-  histogram_tester.ExpectUniqueSample(kRemovalStatusProfileMetric, true, 1);
-  histogram_tester.ExpectUniqueSample(kRemovalStatusAccountMetric, true, 1);
-}
-
-TEST_F(
-    PasswordManagerUpmActivationTest,
-    SetUsesSplitStoresAndUPMForLocal_NoLoginDataFilesCreatedForDeactivatedAccountUsers) {
-  // This test simulated a case when the GMS Core version was manually
-  // downgraded after UPM activation.
-  // In this test UPM should get deactivated because of low GMS Core version.
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-
-  // The initial state of the test is that the user is activated for UPM with
-  // split stores and the login data files were deleted.
-  pref_service()->SetInteger(kPasswordsUseUPMLocalAndSeparateStores,
-                             static_cast<int>(kOn));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-
-  base::FilePath profile_db_path = login_db_directory().Append(
-      password_manager::kLoginDataForProfileFileName);
-  base::FilePath account_db_path = login_db_directory().Append(
-      password_manager::kLoginDataForAccountFileName);
-
-  base::DeleteFile(profile_db_path);
-  base::DeleteFile(account_db_path);
-
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  // The user was deactivated and there are still no login data files.
-  EXPECT_EQ(pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-            static_cast<int>(kOff));
-  EXPECT_FALSE(PathExists(profile_db_path));
-  EXPECT_FALSE(PathExists(account_db_path));
-}
-
-// Integration test for UsesSplitStoresAndUPMForLocal(), which emulates restarts
-// by creating and destroying TestingProfiles. This doesn't exercise any of the
-// Java layers.
-// TODO(b/324196888): Replace with PRE_ AndroidBrowserTests when those
-// are supported, preferably using a FakePasswordStoreAndroidBackend.
-class UsesSplitStoresAndUPMForLocalTest : public ::testing::Test {
- public:
-  UsesSplitStoresAndUPMForLocalTest() {
-    feature_list_.InitAndDisableFeature(
-        password_manager::features::kLoginDbDeprecationAndroid);
-
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        syncer::kSyncDeferredStartupTimeoutSeconds, "0");
-    // Override the GMS version to be big enough for local UPM support, so these
-    // tests still pass in bots with an outdated version.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion()));
-  }
-
-  // Can be invoked more than once, calling DestroyProfile() in-between.
-  // Most of the relevant sync/passwords state is kept between calls.
-  void CreateProfile() {
-    ASSERT_FALSE(profile_) << "Call DestroyProfile() first";
-
-    // Use a fixed profile path, so files like the LoginDBs are kept.
-    TestingProfile::Builder builder;
-    builder.SetPath(profile_path_);
-
-    // Similarly, use a fixed `user_pref_store_`.
-    scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry =
-        base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
-    RegisterUserProfilePrefs(pref_registry.get());
-    builder.SetPrefService(
-        std::make_unique<sync_preferences::TestingPrefServiceSyncable>(
-            base::MakeRefCounted<TestingPrefStore>(),
-            base::MakeRefCounted<TestingPrefStore>(),
-            base::MakeRefCounted<TestingPrefStore>(),
-            /*user_pref_store=*/user_pref_store_,
-            base::MakeRefCounted<TestingPrefStore>(), pref_registry,
-            std::make_unique<PrefNotifierImpl>()));
-
-    // Add the real factories for Sync/Passwords but not the IdentityManager,
-    // which is harder to control.
-    builder.AddTestingFactories(IdentityTestEnvironmentProfileAdaptor::
-                                    GetIdentityTestEnvironmentFactories());
-    builder.AddTestingFactories(
-        {TestingProfile::TestingFactory{
-             TrustedVaultServiceFactory::GetInstance(),
-             TrustedVaultServiceFactory::GetDefaultFactory()},
-         // Unretained() is safe because `this` outlives `profile_`.
-         TestingProfile::TestingFactory{
-             SyncServiceFactory::GetInstance(),
-             base::BindRepeating(
-                 &UsesSplitStoresAndUPMForLocalTest::BuildSyncService,
-                 base::Unretained(this))}});
-    profile_ = builder.Build();
-  }
-
-  void SetUpPasswordStoresWithBuiltInBackend() {
-    // This block of tests is designed to test the behavior of login database
-    // (namely that the profile database file is renamed to be the account
-    // database file when using the split stores feature).
-    std::unique_ptr<password_manager::LoginDatabase> login_db(
-        password_manager::CreateLoginDatabaseForProfileStorage(
-            profile_->GetPath(), profile_->GetPrefs()));
-    password_manager::LoginDatabase* login_db_ptr = login_db.get();
-    std::unique_ptr<password_manager::PasswordStoreBackend> profile_backend =
-        std::make_unique<password_manager::PasswordStoreBuiltInBackend>(
-            std::move(login_db),
-            syncer::WipeModelUponSyncDisabledBehavior::kNever,
-            profile_->GetPrefs());
-    auto is_db_empty_cb =
-        base::BindPostTaskToCurrentDefault(base::BindRepeating(
-            &password_manager::IntermediateCallbackForSettingPrefs,
-            profile_backend->AsWeakPtr(),
-            base::BindRepeating(
-                &password_manager::SetEmptyStorePref, profile_->GetPrefs(),
-                password_manager::prefs::kEmptyProfileStoreLoginDatabase)));
-    login_db_ptr->SetIsEmptyCb(std::move(is_db_empty_cb));
-    ProfilePasswordStoreFactory::GetInstance()->SetTestingFactory(
-        profile_.get(),
-        base::BindRepeating(
-            &password_manager::BuildPasswordStoreWithArgs<
-                content::BrowserContext, password_manager::PasswordStore,
-                std::unique_ptr<password_manager::PasswordStoreBackend>>,
-            base::Passed(std::move(profile_backend))));
-
-    std::unique_ptr<password_manager::PasswordStoreBackend> account_backend =
-        std::make_unique<password_manager::PasswordStoreBuiltInBackend>(
-            password_manager::CreateLoginDatabaseForAccountStorage(
-                profile_->GetPath(), profile_->GetPrefs()),
-            syncer::WipeModelUponSyncDisabledBehavior::kAlways,
-            profile_->GetPrefs());
-    AccountPasswordStoreFactory::GetInstance()->SetTestingFactory(
-        profile_.get(),
-        base::BindRepeating(
-            &password_manager::BuildPasswordStoreWithArgs<
-                content::BrowserContext, password_manager::PasswordStore,
-                std::unique_ptr<password_manager::PasswordStoreBackend>>,
-            base::Passed(std::move(account_backend))));
-  }
-
-  void SetUpPasswordStoresWithFakeBackend() {
-    std::unique_ptr<password_manager::PasswordStoreBackend> profile_backend =
-        std::make_unique<FakePasswordStoreAndroidBackend>(
-            /*is_account_backend=*/false);
-    ProfilePasswordStoreFactory::GetInstance()->SetTestingFactory(
-        profile_.get(),
-        base::BindRepeating(
-            &password_manager::BuildPasswordStoreWithArgs<
-                content::BrowserContext, password_manager::PasswordStore,
-                std::unique_ptr<password_manager::PasswordStoreBackend>>,
-            base::Passed(std::move(profile_backend))));
-
-    std::unique_ptr<password_manager::PasswordStoreBackend> account_backend =
-        std::make_unique<FakePasswordStoreAndroidBackend>(
-            /*is_account_backend=*/true);
-    AccountPasswordStoreFactory::GetInstance()->SetTestingFactory(
-        profile_.get(),
-        base::BindRepeating(
-            &password_manager::BuildPasswordStoreWithArgs<
-                content::BrowserContext, password_manager::PasswordStore,
-                std::unique_ptr<password_manager::PasswordStoreBackend>>,
-            base::Passed(std::move(account_backend))));
-  }
-
-  void CreateSyncService() {
-    // `identity_test_env_adaptor_` is initialized lazily with the SyncService,
-    // force it to happen now.
-    ASSERT_FALSE(identity_test_env_adaptor_);
-    sync_service();
-    ASSERT_TRUE(identity_test_env_adaptor_);
-  }
-
-  void DestroyProfile() {
-    ASSERT_TRUE(profile_) << "Call CreateProfile() first";
-
-    task_environment_.RunUntilIdle();
-    identity_test_env_adaptor_.reset();
-    profile_.reset();
-  }
-
-  std::unique_ptr<KeyedService> BuildSyncService(
-      content::BrowserContext* context) {
-    identity_test_env_adaptor_ =
-        std::make_unique<IdentityTestEnvironmentProfileAdaptor>(
-            Profile::FromBrowserContext(context));
-    if (signed_in_) {
-      // The refresh token is not persisted in the test, so set it again before
-      // creating the SyncService.
-      identity_test_env_adaptor_->identity_test_env()
-          ->SetRefreshTokenForPrimaryAccount();
-    }
-
-    return SyncServiceFactory::GetDefaultFactory(
-               fake_server::CreateFakeServerHttpPostProviderFactory(
-                   fake_server_.AsWeakPtr()))
-        .Run(context);
-  }
-
-  void SignInAndEnableSync() {
-    ASSERT_TRUE(identity_test_env_adaptor_);
-    signin::IdentityTestEnvironment* env =
-        identity_test_env_adaptor_->identity_test_env();
-    ASSERT_FALSE(env->identity_manager()->HasPrimaryAccount(
-        signin::ConsentLevel::kSync));
-    env->SetAutomaticIssueOfAccessTokens(true);
-    env->MakePrimaryAccountAvailable("foo@gmail.com",
-                                     signin::ConsentLevel::kSync);
-    signed_in_ = true;
-
-    // Sync few types to avoid setting up dependencies for most of them.
-    std::unique_ptr<syncer::SyncSetupInProgressHandle> handle =
-        sync_service()->GetSetupInProgressHandle();
-    sync_service()->GetUserSettings()->SetSelectedTypes(
-        /*sync_everything=*/false, {syncer::UserSelectableType::kPreferences,
-                                    syncer::UserSelectableType::kPasswords});
-    sync_service()->GetUserSettings()->SetInitialSyncFeatureSetupComplete(
-        syncer::SyncFirstSetupCompleteSource::BASIC_FLOW);
-  }
-
-  syncer::SyncService* sync_service() {
-    return SyncServiceFactory::GetForProfile(profile_.get());
-  }
-
-  password_manager::PasswordStoreInterface* profile_password_store() {
-    return ProfilePasswordStoreFactory::GetForProfile(
-               profile_.get(), ServiceAccessType::IMPLICIT_ACCESS)
-        .get();
-  }
-
-  password_manager::PasswordStoreInterface* account_password_store() {
-    return AccountPasswordStoreFactory::GetForProfile(
-               profile_.get(), ServiceAccessType::IMPLICIT_ACCESS)
-        .get();
-  }
-
-  PrefService* pref_service() { return profile_->GetPrefs(); }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-  content::BrowserTaskEnvironment task_environment_;
-  const base::FilePath profile_path_ =
-      base::CreateUniqueTempDirectoryScopedToTest();
-  const scoped_refptr<TestingPrefStore> user_pref_store_ =
-      base::MakeRefCounted<TestingPrefStore>();
-  const ScopedTestingLocalState local_state_ =
-      ScopedTestingLocalState(TestingBrowserProcess::GetGlobal());
-  fake_server::FakeServer fake_server_;
-  std::unique_ptr<TestingProfile> profile_;
-  std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
-      identity_test_env_adaptor_;
-  bool signed_in_ = false;
-};
-
-TEST_F(UsesSplitStoresAndUPMForLocalTest, SignedOutWithoutPasswords) {
-  {
-    // Prevent activation on the first run by faking an outdated GmsCore.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-    CreateProfile();
-    ASSERT_FALSE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-
-  {
-    // Now GmsCore was upgraded and activation can proceed.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion()));
-    CreateProfile();
-    EXPECT_TRUE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-}
-
-TEST_F(UsesSplitStoresAndUPMForLocalTest, SignedOutWithPasswords) {
-  {
-    // Set up a signed-out user, with saved passwords. Prevent activation before
-    // the passwords are added, by faking an outdated GmsCore.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-    CreateProfile();
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-    profile_password_store()->AddLogin(MakeExampleForm());
-    ASSERT_FALSE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-
-  {
-    // Now GmsCore was upgraded, so the migration gets scheduled.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion()));
-    CreateProfile();
-
-    // Until the migration finishes, UsesSplitStoresAndUPMForLocal() should be
-    // false and password sync should be suppressed.
-    ASSERT_FALSE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-    SignInAndEnableSync();
-    ASSERT_TRUE(
-        SyncDataTypeActiveWaiter(sync_service(), syncer::PREFERENCES).Wait());
-    ASSERT_FALSE(sync_service()->GetUserSettings()->GetSelectedTypes().Has(
-        syncer::UserSelectableType::kPasswords));
-
-    // Pretend the migration finished.
-    // TODO(b/324196888): Once the migration is implemented, make this a
-    // call to a fake instead of directly setting the pref.
-    pref_service()->SetInteger(
-        password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(kOn));
-    EXPECT_TRUE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    ASSERT_TRUE(
-        SyncDataTypeActiveWaiter(sync_service(), syncer::PASSWORDS).Wait());
-
-    DestroyProfile();
-  }
-}
-
-TEST_F(UsesSplitStoresAndUPMForLocalTest, SyncingHealthy) {
-  {
-    // Prevent activation before sync is enabled, by faking an outdated GmsCore.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-    CreateProfile();
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-    profile_password_store()->AddLogin(MakeExampleForm());
-    SignInAndEnableSync();
-    ASSERT_TRUE(
-        SyncDataTypeActiveWaiter(sync_service(), syncer::PASSWORDS).Wait());
-    pref_service()->SetInteger(
-        password_manager::prefs::kCurrentMigrationVersionToGoogleMobileServices,
-        1);
-    ASSERT_FALSE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-
-  {
-    // Now GmsCore was upgraded and activation can proceed.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion()));
-
-    // Creating the profile will already activate the user.
-    CreateProfile();
-    // Since the user is activated, the built-in backend is no longe initialize.
-    // Use a fake backend instead.
-    SetUpPasswordStoresWithFakeBackend();
-    CreateSyncService();
-    ASSERT_TRUE(
-        SyncDataTypeActiveWaiter(sync_service(), syncer::PASSWORDS).Wait());
-    EXPECT_TRUE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-}
-
-TEST_F(UsesSplitStoresAndUPMForLocalTest, SyncingButUnenrolledAndM4Enabled) {
-  // Test setup where one password was saved to profile store and user is
-  // unenrolled from UPM.
-  {
-    // Prevent activation before sync is enabled, by faking an outdated GmsCore.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-    CreateProfile();
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-    profile_password_store()->AddLogin(MakeExampleForm());
-    SignInAndEnableSync();
-    ASSERT_TRUE(
-        SyncDataTypeActiveWaiter(sync_service(), syncer::PASSWORDS).Wait());
-    pref_service()->SetBoolean(
-        password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-        true);
-    pref_service()->SetInteger(
-        password_manager::prefs::kCurrentMigrationVersionToGoogleMobileServices,
-        1);
-    ASSERT_FALSE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-
-  {
-    // Now GmsCore was upgraded and activation can proceed.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion()));
-    CreateProfile();
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-
-    // The migration is pending.
-    EXPECT_EQ(
-        pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-        static_cast<int>(kOffAndMigrationPending));
-
-    // Passwords is still in the profile, it was not moved to account even
-    // though user was syncing.
-    password_manager::PasswordStoreResultsObserver profile_store_observer;
-    password_manager::PasswordStoreResultsObserver account_store_observer;
-    profile_password_store()->GetAllLogins(profile_store_observer.GetWeakPtr());
-    account_password_store()->GetAllLogins(account_store_observer.GetWeakPtr());
-    EXPECT_EQ(profile_store_observer.WaitForResults().size(), 1u);
-    EXPECT_EQ(account_store_observer.WaitForResults().size(), 0u);
-    DestroyProfile();
-  }
-}
-
-TEST_F(UsesSplitStoresAndUPMForLocalTest,
-       SyncingButNoInitialUPMMigrationAndM4Enabled) {
-  // Test setup where one password was saved to profile store and user is
-  // enrolled into original UPM.
-  {
-    // Prevent activation before sync is enabled, by faking an outdated GmsCore.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion() - 1));
-    CreateProfile();
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-    profile_password_store()->AddLogin(MakeExampleForm());
-    SignInAndEnableSync();
-    ASSERT_TRUE(
-        SyncDataTypeActiveWaiter(sync_service(), syncer::PASSWORDS).Wait());
-    pref_service()->SetInteger(
-        password_manager::prefs::kCurrentMigrationVersionToGoogleMobileServices,
-        0);
-    ASSERT_FALSE(UsesSplitStoresAndUPMForLocal(pref_service()));
-    DestroyProfile();
-  }
-
-  {
-    // Now GmsCore was upgraded and activation can proceed.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-        base::NumberToString(GetLocalUpmMinGmsVersion()));
-    CreateProfile();
-    SetUpPasswordStoresWithBuiltInBackend();
-    CreateSyncService();
-    // The migration is pending.
-    EXPECT_EQ(
-        pref_service()->GetInteger(kPasswordsUseUPMLocalAndSeparateStores),
-        static_cast<int>(kOffAndMigrationPending));
-
-    // Passwords is still in the profile, it was not moved to account even
-    // though user was syncing.
-    password_manager::PasswordStoreResultsObserver profile_store_observer;
-    password_manager::PasswordStoreResultsObserver account_store_observer;
-    profile_password_store()->GetAllLogins(profile_store_observer.GetWeakPtr());
-    account_password_store()->GetAllLogins(account_store_observer.GetWeakPtr());
-    EXPECT_EQ(profile_store_observer.WaitForResults().size(), 1u);
-    EXPECT_EQ(account_store_observer.WaitForResults().size(), 0u);
-    DestroyProfile();
-  }
-}
-
-struct GetPasswordAccessLossWarningTypeTestCase {
-  std::string test_case_desc;
-  std::string gms_core_version;
-  bool migration_attempted;
-  bool local_passwords_migration_failed;
-  bool empty_profile_store;
-  bool is_auto;
-  GmsVersionCohort expected_gms_cohort;
-  PasswordAccessLossWarningType expected_type;
-};
-
-class GetPasswordAccessLossWarningTypeTest
-    : public PasswordManagerAndroidUtilTest,
-      public testing::WithParamInterface<
-          GetPasswordAccessLossWarningTypeTestCase> {
- protected:
-  void SetUp() override {
-    GetPasswordAccessLossWarningTypeTestCase test_case = GetParam();
-
-    int use_upm_and_separate_stores = 0;
-    if (!test_case.migration_attempted) {
-      use_upm_and_separate_stores = static_cast<int>(kOff);
-    } else if (test_case.local_passwords_migration_failed) {
-      use_upm_and_separate_stores = static_cast<int>(kOffAndMigrationPending);
-    } else {
-      use_upm_and_separate_stores = static_cast<int>(kOn);
-    }
-    pref_service()->SetInteger(
-        password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        use_upm_and_separate_stores);
-    pref_service()->SetBoolean(
-        password_manager::prefs::kEmptyProfileStoreLoginDatabase,
-        test_case.empty_profile_store);
-  }
-};
-
-TEST_P(GetPasswordAccessLossWarningTypeTest, GetPasswordAccessLossWarningType) {
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid) &&
-      GetParam().local_passwords_migration_failed) {
-    // When the deprecation is enabled, the migration doesn't happen anymore
-    // and this test is not applicable.
-    GTEST_SKIP();
-  }
-  if (base::android::BuildInfo::GetInstance()->is_automotive() !=
-      GetParam().is_auto) {
-    GTEST_SKIP() << "Automotive tests don't need to run on non-auto devices "
-                    "and vice-versa.";
-  }
-
-  base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
-      GetParam().gms_core_version);
-
-  EXPECT_EQ(GetParam().expected_gms_cohort,
-            password_manager_android_util::GetGmsVersionCohort());
-
-  // This call is needed to set the variable whether the migration is failed.
-  SetUsesSplitStoresAndUPMForLocal(pref_service(), login_db_directory(),
-                                   GetMockBridgeWithBackendPresent());
-
-  PasswordAccessLossWarningType result =
-      GetPasswordAccessLossWarningType(pref_service());
-
-  EXPECT_EQ(GetParam().expected_type, result);
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    GetPasswordAccessLossWarningTypeTest,
-    testing::Values(
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"NoGmsNoPwds",
-            /*gms_core_version=*/"",
-            /*migration_attempted=*/false,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/true,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kNoGms,
-            /*expected_type=*/PasswordAccessLossWarningType::kNoGmsCore),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"NoGmsButPwds",
-            /*gms_core_version=*/"",
-            /*migration_attempted=*/false,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kNoGms,
-            /*expected_type=*/PasswordAccessLossWarningType::kNoGmsCore),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"NoUpmNoPwds",
-            /*gms_core_version=*/"222912000",
-            /*migration_attempted=*/false,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/true,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kNoUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kNoUpm),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"NoUpmButPwds",
-            /*gms_core_version=*/"222912000",
-            /*migration_attempted=*/false,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kNoUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kNoUpm),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"AccountGmsNoPwds",
-            /*gms_core_version=*/"223012000",
-            /*migration_attempted=*/false,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/true,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kOnlyAccountUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kOnlyAccountUpm),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"AccountGmsLocalPwds",
-            /*gms_core_version=*/"223012000",
-            /*migration_attempted=*/true,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kOnlyAccountUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kOnlyAccountUpm),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"MigrationFailed",
-            /*gms_core_version=*/"240212000",
-            /*migration_attempted=*/true,
-            /*local_passwords_migration_failed=*/true,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kFullUpmSupport,
-            /*expected_type=*/
-            PasswordAccessLossWarningType::kNewGmsCoreMigrationFailed),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"MigrationSucceeded",
-            /*gms_core_version=*/"240212000",
-            /*migration_attempted=*/true,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/false,
-            /*expected_gms_cohort=*/GmsVersionCohort::kFullUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kNone),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"AccountGmsLocalPwdsAuto",
-            /*gms_core_version=*/"241412000",
-            /*migration_attempted=*/false,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/true,
-            /*expected_gms_cohort=*/GmsVersionCohort::kOnlyAccountUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kOnlyAccountUpm),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"MigrationFailedAuto",
-            /*gms_core_version=*/"241512000",
-            /*migration_attempted=*/true,
-            /*local_passwords_migration_failed=*/true,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/true,
-            /*expected_gms_cohort=*/GmsVersionCohort::kFullUpmSupport,
-            /*expected_type=*/
-            PasswordAccessLossWarningType::kNewGmsCoreMigrationFailed),
-        GetPasswordAccessLossWarningTypeTestCase(
-            /*test_case_desc=*/"MigrationSucceededAuto",
-            /*gms_core_version=*/"241512000",
-            /*migration_attempted=*/true,
-            /*local_passwords_migration_failed=*/false,
-            /*empty_profile_store=*/false,
-            /*is_auto=*/true,
-            /*expected_gms_cohort=*/GmsVersionCohort::kFullUpmSupport,
-            /*expected_type=*/PasswordAccessLossWarningType::kNone)),
-    [](const ::testing::TestParamInfo<GetPasswordAccessLossWarningTypeTestCase>&
-           info) { return info.param.test_case_desc; });
-
 }  // namespace
 }  // namespace password_manager_android_util
diff --git a/chrome/browser/password_manager/android/password_manager_eviction_util_unittest.cc b/chrome/browser/password_manager/android/password_manager_eviction_util_unittest.cc
index 0a1c826..ae99a03 100644
--- a/chrome/browser/password_manager/android/password_manager_eviction_util_unittest.cc
+++ b/chrome/browser/password_manager/android/password_manager_eviction_util_unittest.cc
@@ -38,8 +38,6 @@
       0);
   test_pref_service_.registry()->RegisterIntegerPref(
       password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores, 0);
-  test_pref_service_.registry()->RegisterDoublePref(
-      password_manager::prefs::kTimeOfLastMigrationAttempt, 0.0);
   test_pref_service_.registry()->RegisterBooleanPref(
       password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
 }
diff --git a/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.cc b/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.cc
deleted file mode 100644
index 562b0bd..0000000
--- a/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.cc
+++ /dev/null
@@ -1,617 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.h"
-
-#include <optional>
-#include <vector>
-
-#include "base/barrier_callback.h"
-#include "base/feature_list.h"
-#include "base/functional/bind.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/strcat.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
-#include "chrome/browser/password_manager/android/password_manager_eviction_util.h"
-#include "chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h"
-#include "chrome/browser/password_manager/android/password_settings_updater_android_bridge_helper.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_manager_setting.h"
-#include "components/password_manager/core/browser/password_sync_util.h"
-#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
-#include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/public/base/signin_pref_names.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/sync/base/features.h"
-#include "components/sync/base/user_selectable_type.h"
-#include "components/sync/service/sync_service.h"
-#include "components/sync/service/sync_user_settings.h"
-
-using password_manager::PasswordManagerSetting;
-using password_manager::PasswordSettingsUpdaterAndroidBridgeHelper;
-using password_manager::UsesSplitStoresAndUPMForLocal;
-using password_manager_upm_eviction::IsCurrentUserEvicted;
-
-namespace {
-
-using Consumer =
-    password_manager::PasswordSettingsUpdaterAndroidReceiverBridge::Consumer;
-using SyncingAccount = password_manager::
-    PasswordSettingsUpdaterAndroidReceiverBridge::SyncingAccount;
-using password_manager::prefs::UseUpmLocalAndSeparateStoresState;
-
-const std::vector<PasswordManagerSetting> GetAllPasswordSettings() {
-  return base::FeatureList::IsEnabled(
-             password_manager::features::kBiometricTouchToFill)
-             ? std::vector(
-                   {PasswordManagerSetting::kOfferToSavePasswords,
-                    PasswordManagerSetting::kAutoSignIn,
-                    PasswordManagerSetting::kBiometricReauthBeforePwdFilling})
-             : std::vector({PasswordManagerSetting::kOfferToSavePasswords,
-                            PasswordManagerSetting::kAutoSignIn});
-}
-
-constexpr PasswordManagerSetting kMigratablePasswordSettings[] = {
-    PasswordManagerSetting::kOfferToSavePasswords,
-    PasswordManagerSetting::kAutoSignIn,
-};
-
-// Returns the preference in which a setting value coming from Google Mobile
-// Services should be stored.
-const PrefService::Preference* GetGMSPrefFromSetting(
-    PrefService* pref_service,
-    PasswordManagerSetting setting) {
-  switch (setting) {
-    case PasswordManagerSetting::kOfferToSavePasswords:
-      return pref_service->FindPreference(
-          password_manager::prefs::kOfferToSavePasswordsEnabledGMS);
-    case PasswordManagerSetting::kAutoSignIn:
-      return pref_service->FindPreference(
-          password_manager::prefs::kAutoSignInEnabledGMS);
-    case PasswordManagerSetting::kBiometricReauthBeforePwdFilling:
-      return pref_service->FindPreference(
-          password_manager::prefs::kBiometricAuthenticationBeforeFilling);
-  }
-}
-
-// Returns the cross-platform preferences in which password manager settings
-// are stored. These are not directly used on Android when the unified password
-// manager is enabled.
-// TODO(crbug.com/394299374): Remove this after login DB deprecation.
-const PrefService::Preference* GetRegularPrefFromSetting(
-    PrefService* pref_service,
-    PasswordManagerSetting setting) {
-  switch (setting) {
-    case PasswordManagerSetting::kOfferToSavePasswords:
-      return pref_service->FindPreference(
-          password_manager::prefs::kCredentialsEnableService);
-    case PasswordManagerSetting::kAutoSignIn:
-      return pref_service->FindPreference(
-          password_manager::prefs::kCredentialsEnableAutosignin);
-    // Never existed in Chrome on Android before.
-    case PasswordManagerSetting::kBiometricReauthBeforePwdFilling:
-      return pref_service->FindPreference(
-          password_manager::prefs::kBiometricAuthenticationBeforeFilling);
-  }
-}
-
-bool HasChosenToSyncPreferences(const syncer::SyncService* sync_service) {
-  return sync_service && sync_service->GetDisableReasons().empty() &&
-         sync_service->GetUserSettings()->GetSelectedTypes().Has(
-             syncer::UserSelectableType::kPreferences);
-}
-
-bool DoesUpmPrefAllowForSettingsMigration(PrefService* pref_service) {
-  return static_cast<UseUpmLocalAndSeparateStoresState>(
-             pref_service->GetInteger(
-                 password_manager::prefs::
-                     kPasswordsUseUPMLocalAndSeparateStores)) !=
-         UseUpmLocalAndSeparateStoresState::kOff;
-}
-
-bool ShouldMigrateLocalSettings(PrefService* pref_service,
-                                bool is_password_sync_enabled) {
-  // Settings should be migrated if the user is enrolled in UPM with local
-  // passwords and they have never successfully completed settings migration.
-  return !is_password_sync_enabled &&
-         !pref_service->GetBoolean(
-             password_manager::prefs::kSettingsMigratedToUPMLocal) &&
-         DoesUpmPrefAllowForSettingsMigration(pref_service);
-}
-
-// This function is called after a setting is fetched from
-// GMS Core to update the cache. Updating the non-cache (regular)
-// prefs is also done in cases where sync isn't running so that the value
-// is up-to-data in case of rollback.
-bool ShouldWriteToRegularPref(syncer::SyncService* sync_service,
-                              PrefService* pref_service) {
-  // We should write to regular pref if sync for preferences is disabled and:
-  // 1) User is using upm with local passwords and their settings migration
-  // finished.
-  // 2) User is not using upm with local passwords.
-  bool is_using_upm_with_local_passwords_and_had_settings_migrated =
-      DoesUpmPrefAllowForSettingsMigration(pref_service) &&
-      pref_service->GetBoolean(
-          password_manager::prefs::kSettingsMigratedToUPMLocal);
-  bool is_not_using_upm_with_local_passwords =
-      !DoesUpmPrefAllowForSettingsMigration(pref_service);
-  return !HasChosenToSyncPreferences(sync_service) &&
-         (is_using_upm_with_local_passwords_and_had_settings_migrated ||
-          is_not_using_upm_with_local_passwords);
-}
-
-bool DidAccessingGMSPrefsFailed(
-    const std::vector<PasswordManagerSettingGmsAccessResult>& results) {
-  return !results[0].was_successful || !results[1].was_successful ||
-         results[0].setting == results[1].setting;
-}
-
-std::string_view GetMetricsInfixForSetting(
-    password_manager::PasswordManagerSetting setting) {
-  switch (setting) {
-    case password_manager::PasswordManagerSetting::kOfferToSavePasswords:
-      return "OfferToSavePasswords";
-    case password_manager::PasswordManagerSetting::kAutoSignIn:
-      return "AutoSignIn";
-    case password_manager::PasswordManagerSetting::
-        kBiometricReauthBeforePwdFilling:
-      return "BiometricReauthBeforePwdFilling";
-  }
-}
-
-void RecordFailedMigrationMetric(std::string_view infix_for_setting,
-                                 AndroidBackendAPIErrorCode api_error) {
-  base::UmaHistogramSparse(
-      base::StrCat({"PasswordManager.PasswordSettingsMigrationFailed.",
-                    infix_for_setting, ".APIError2"}),
-      static_cast<int>(api_error));
-}
-
-void RecordMigrationResult(bool result) {
-  base::UmaHistogramBoolean(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", result);
-}
-
-void MarkSettingsMigrationAsSuccessfulIfNothingToMigrate(PrefService* prefs) {
-  if (GetRegularPrefFromSetting(prefs, PasswordManagerSetting::kAutoSignIn)
-          ->IsDefaultValue() &&
-      GetRegularPrefFromSetting(prefs,
-                                PasswordManagerSetting::kOfferToSavePasswords)
-          ->IsDefaultValue()) {
-    RecordMigrationResult(true);
-    prefs->SetBoolean(password_manager::prefs::kSettingsMigratedToUPMLocal,
-                      true);
-  }
-}
-
-}  // namespace
-
-PasswordManagerSettingsServiceAndroidMigrationImpl::
-    PasswordManagerSettingsServiceAndroidMigrationImpl(
-        PrefService* pref_service,
-        syncer::SyncService* sync_service)
-    : pref_service_(pref_service), sync_service_(sync_service) {
-  CHECK(pref_service_);
-  bridge_helper_ = PasswordSettingsUpdaterAndroidBridgeHelper::Create();
-  lifecycle_helper_ = std::make_unique<PasswordManagerLifecycleHelperImpl>();
-  Init();
-}
-
-// Constructor for tests
-PasswordManagerSettingsServiceAndroidMigrationImpl::
-    PasswordManagerSettingsServiceAndroidMigrationImpl(
-        base::PassKey<
-            class PasswordManagerSettingsServiceAndroidMigrationImplBaseTest>,
-        PrefService* pref_service,
-        syncer::SyncService* sync_service,
-        std::unique_ptr<PasswordSettingsUpdaterAndroidBridgeHelper>
-            bridge_helper,
-        std::unique_ptr<PasswordManagerLifecycleHelper> lifecycle_helper)
-    : pref_service_(pref_service),
-      sync_service_(sync_service),
-      bridge_helper_(std::move(bridge_helper)),
-      lifecycle_helper_(std::move(lifecycle_helper)) {
-  CHECK(pref_service_);
-  CHECK(bridge_helper_);
-  Init();
-}
-
-PasswordManagerSettingsServiceAndroidMigrationImpl::
-    ~PasswordManagerSettingsServiceAndroidMigrationImpl() {
-  if (lifecycle_helper_) {
-    lifecycle_helper_->UnregisterObserver();
-  }
-}
-
-bool PasswordManagerSettingsServiceAndroidMigrationImpl::IsSettingEnabled(
-    PasswordManagerSetting setting) const {
-  const PrefService::Preference* regular_pref =
-      GetRegularPrefFromSetting(pref_service_, setting);
-  CHECK(regular_pref);
-
-  if (!UsesUPMBackend()) {
-    return regular_pref->GetValue()->GetBool();
-  }
-
-  if (regular_pref->IsManaged() || regular_pref->IsManagedByCustodian()) {
-    return regular_pref->GetValue()->GetBool();
-  }
-
-  // Until the settings migration finished successfully, Chrome's setting value
-  // will be returned.
-  if (!is_password_sync_enabled_ &&
-      !pref_service_->GetBoolean(
-          password_manager::prefs::kSettingsMigratedToUPMLocal)) {
-    return regular_pref->GetValue()->GetBool();
-  }
-
-  const PrefService::Preference* android_pref =
-      GetGMSPrefFromSetting(pref_service_, setting);
-  CHECK(android_pref);
-  return android_pref->GetValue()->GetBool();
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    RequestSettingsFromBackend() {
-  if (!UsesUPMBackend()) {
-    return;
-  }
-  FetchSettings();
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::TurnOffAutoSignIn() {
-  if (!UsesUPMBackend()) {
-    pref_service_->SetBoolean(
-        password_manager::prefs::kCredentialsEnableAutosignin, false);
-    return;
-  }
-  if (!HasChosenToSyncPreferences(sync_service_)) {
-    pref_service_->SetBoolean(
-        password_manager::prefs::kCredentialsEnableAutosignin, false);
-  }
-
-  pref_service_->SetBoolean(password_manager::prefs::kAutoSignInEnabledGMS,
-                            false);
-  std::optional<SyncingAccount> account = std::nullopt;
-  if (is_password_sync_enabled_) {
-    account = SyncingAccount(sync_service_->GetAccountInfo().email);
-  }
-  // TODO(crbug.com/40285405): Implement retries for writing to GMSCore.
-  bridge_helper_->SetPasswordSettingValue(
-      account, PasswordManagerSetting::kAutoSignIn, false);
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::Init() {
-  CHECK(bridge_helper_);
-  // TODO(crbug.com/40282601): Copy the pref values to GMSCore for local users.
-  bridge_helper_->SetConsumer(weak_ptr_factory_.GetWeakPtr());
-
-  lifecycle_helper_->RegisterObserver(base::BindRepeating(
-      &PasswordManagerSettingsServiceAndroidMigrationImpl::OnChromeForegrounded,
-      weak_ptr_factory_.GetWeakPtr()));
-  is_password_sync_enabled_ = false;
-  if (sync_service_) {
-    is_password_sync_enabled_ =
-        password_manager::sync_util::HasChosenToSyncPasswords(sync_service_);
-    // The `sync_service_` can be null when --disable-sync has been passed in as
-    // a command line flag.
-    sync_service_->AddObserver(this);
-  }
-
-  pref_change_registrar_.Init(pref_service_);
-  pref_change_registrar_.Add(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      base::BindRepeating(&PasswordManagerSettingsServiceAndroidMigrationImpl::
-                              OnUnenrollmentPreferenceChanged,
-                          weak_ptr_factory_.GetWeakPtr()));
-
-  if (ShouldMigrateLocalSettings(pref_service_, is_password_sync_enabled_)) {
-    MarkSettingsMigrationAsSuccessfulIfNothingToMigrate(pref_service_);
-    // If the migration was marked as done because there was nothing to migrate,
-    // there is no reason to create the migration callback.
-    if (!pref_service_->GetBoolean(
-            password_manager::prefs::kSettingsMigratedToUPMLocal)) {
-      start_migration_callback_ =
-          base::BarrierCallback<PasswordManagerSettingGmsAccessResult>(
-              2, base::BindOnce(
-                     &PasswordManagerSettingsServiceAndroidMigrationImpl::
-                         MigratePrefsIfNeeded,
-                     weak_ptr_factory_.GetWeakPtr()));
-    }
-  }
-
-  // Unset the pref that marks the settings migration done, if the user is not
-  // eligible for split stores and UPM for local. This is useful in case of
-  // rollback and it also fixes the issue of the pref being set to true for
-  // not-yet-enrolled users that had default prefs.
-  if (password_manager_android_util::GetSplitStoresAndLocalUpmPrefValue(
-          pref_service_) == UseUpmLocalAndSeparateStoresState::kOff) {
-    pref_service_->SetBoolean(
-        password_manager::prefs::kSettingsMigratedToUPMLocal, false);
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    OnChromeForegrounded() {
-  RequestSettingsFromBackend();
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::OnSettingValueFetched(
-    PasswordManagerSetting setting,
-    bool value) {
-  UpdateSettingFetchState(setting);
-  // For the users not using the UPM backend, the setting value should not be
-  // written to the cache and the regular pref, unless this call to
-  // `OnSettingValueFetched` was part of the final fetch after a sync state
-  // change.
-  if (!UsesUPMBackend() && !fetch_after_sync_status_change_in_progress_) {
-    return;
-  }
-
-  WriteToTheCacheAndRegularPref(setting, value);
-  if (start_migration_callback_) {
-    start_migration_callback_.Run(PasswordManagerSettingGmsAccessResult(
-        setting, /*was_successful=*/true));
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::OnSettingValueAbsent(
-    password_manager::PasswordManagerSetting setting) {
-  CHECK(bridge_helper_);
-  UpdateSettingFetchState(setting);
-
-  if (!UsesUPMBackend()) {
-    return;
-  }
-
-  // This code is currently called only for UPM users. If the setting value
-  // is absent in GMSCore, the cached setting value is set to the default
-  // value, which is true for both of the password-related settings:
-  // AutoSignIn and OfferToSavePasswords.
-  WriteToTheCacheAndRegularPref(setting, std::nullopt);
-  if (start_migration_callback_) {
-    start_migration_callback_.Run(PasswordManagerSettingGmsAccessResult(
-        setting, /*was_successful=*/true));
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::OnSettingFetchingError(
-    password_manager::PasswordManagerSetting setting,
-    AndroidBackendAPIErrorCode api_error_code) {
-  CHECK(bridge_helper_);
-  if (!UsesUPMBackend()) {
-    return;
-  }
-  if (start_migration_callback_) {
-    RecordFailedMigrationMetric(GetMetricsInfixForSetting(setting),
-                                api_error_code);
-    start_migration_callback_.Run(PasswordManagerSettingGmsAccessResult(
-        setting, /*was_successful=*/false));
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    OnSuccessfulSettingChange(
-        password_manager::PasswordManagerSetting setting) {
-  CHECK(bridge_helper_);
-  if (!UsesUPMBackend()) {
-    return;
-  }
-  if (migration_finished_callback_) {
-    migration_finished_callback_.Run(PasswordManagerSettingGmsAccessResult(
-        setting, /*was_successful=*/true));
-  }
-}
-void PasswordManagerSettingsServiceAndroidMigrationImpl::OnFailedSettingChange(
-    password_manager::PasswordManagerSetting setting,
-    AndroidBackendAPIErrorCode api_error_code) {
-  CHECK(bridge_helper_);
-  if (!UsesUPMBackend()) {
-    return;
-  }
-  if (migration_finished_callback_) {
-    RecordFailedMigrationMetric(GetMetricsInfixForSetting(setting),
-                                api_error_code);
-    migration_finished_callback_.Run(PasswordManagerSettingGmsAccessResult(
-        setting, /*was_successful=*/false));
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    WriteToTheCacheAndRegularPref(PasswordManagerSetting setting,
-                                  std::optional<bool> value) {
-  const PrefService::Preference* android_pref =
-      GetGMSPrefFromSetting(pref_service_, setting);
-  if (value.has_value()) {
-    pref_service_->SetBoolean(android_pref->name(), value.value());
-  } else {
-    pref_service_->ClearPref(android_pref->name());
-  }
-
-  // Updating the regular pref now will ensure that if passwods sync turns off
-  // the regular pref contains the latest setting value. This can only be done
-  // when preference syncing is off, otherwise it might cause sync cycles.
-  // When sync is on, the regular preference gets updated via sync, so this
-  // step is not necessary.
-  if (ShouldWriteToRegularPref(sync_service_, pref_service_)) {
-    const PrefService::Preference* regular_pref =
-        GetRegularPrefFromSetting(pref_service_, setting);
-    if (value.has_value()) {
-      pref_service_->SetBoolean(regular_pref->name(), value.value());
-    } else {
-      pref_service_->ClearPref(regular_pref->name());
-    }
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::OnStateChanged(
-    syncer::SyncService* sync) {
-  CHECK(sync);
-  // Return early if the setting didn't change and no sync errors were resolved.
-  bool is_password_sync_enabled =
-      password_manager::sync_util::HasChosenToSyncPasswords(sync_service_);
-  if (is_password_sync_enabled == is_password_sync_enabled_) {
-    return;
-  }
-
-  is_password_sync_enabled_ = is_password_sync_enabled;
-
-  if (is_password_sync_enabled_ && IsCurrentUserEvicted(pref_service_)) {
-    return;
-  }
-
-  // If sync just turned off, but the client was unenrolled prior to the change
-  // and they are not using local storage support, it means that there is no
-  // backend to talk to and Chrome will be reading the settings from the regular
-  // prefs, so there is no point in making a request for new settings values.
-  // Users not syncing passwords that have local storage support ignore
-  // unenrollment and need to fetch new settings from the local backend to
-  // replace the account ones.
-  if (!is_password_sync_enabled_ && IsCurrentUserEvicted(pref_service_) &&
-      !UsesSplitStoresAndUPMForLocal(pref_service_)) {
-    return;
-  }
-
-  // Fetch settings from the backend to align values stored in GMS Core and
-  // Chrome.
-  fetch_after_sync_status_change_in_progress_ = true;
-  for (PasswordManagerSetting setting : GetAllPasswordSettings()) {
-    awaited_settings_.insert(setting);
-  }
-  FetchSettings();
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    UpdateSettingFetchState(PasswordManagerSetting received_setting) {
-  if (!fetch_after_sync_status_change_in_progress_) {
-    return;
-  }
-
-  awaited_settings_.erase(received_setting);
-  if (awaited_settings_.empty()) {
-    fetch_after_sync_status_change_in_progress_ = false;
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::FetchSettings() {
-  CHECK(bridge_helper_);
-  // This code would not be executed for syncing users who are unenrolled.
-  CHECK(!is_password_sync_enabled_ || !IsCurrentUserEvicted(pref_service_));
-  std::optional<SyncingAccount> account = std::nullopt;
-  bool is_final_fetch_for_local_user_without_upm =
-      fetch_after_sync_status_change_in_progress_ &&
-      !is_password_sync_enabled_ &&
-      !UsesSplitStoresAndUPMForLocal(pref_service_);
-  if (is_password_sync_enabled_ || is_final_fetch_for_local_user_without_upm) {
-    // Note: This method also handles the case where the previously signed-in
-    // account has just signed out. So the account can't be queried via
-    // `sync_service_->GetAccountInfo().email` but instead needs to be retrieved
-    // via kGoogleServices*Last*SignedInUsername.
-    std::string last_account_pref =
-        pref_service_->GetString(prefs::kGoogleServicesLastSignedInUsername);
-    account = SyncingAccount(last_account_pref);
-  }
-  for (PasswordManagerSetting setting : GetAllPasswordSettings()) {
-    bridge_helper_->GetPasswordSettingValue(account, setting);
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    OnUnenrollmentPreferenceChanged() {
-  if (!IsCurrentUserEvicted(pref_service_)) {
-    // Perform actions that are usually done on startup, but were skipped
-    // for the evicted users.
-    RequestSettingsFromBackend();
-  }
-}
-
-bool PasswordManagerSettingsServiceAndroidMigrationImpl::UsesUPMBackend()
-    const {
-  return password_manager_android_util::ShouldUseUpmWiring(sync_service_,
-                                                           pref_service_);
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::MigratePrefsIfNeeded(
-    const std::vector<PasswordManagerSettingGmsAccessResult>& results) {
-  start_migration_callback_.Reset();
-  // Check if migration should happen.
-  if (!ShouldMigrateLocalSettings(pref_service_, is_password_sync_enabled_)) {
-    return;
-  }
-
-  // Check if getting settings prefs failed. In rare cases (when Chrome was put
-  // into the background with running migration and then to the foreground
-  // again), since the settings from GMS are fetched when foregrounding Chrome,
-  // it might happen that two fetches for the same pref will finish first. We
-  // want to ensure that each one of the settings was fetched successfully.
-  if (DidAccessingGMSPrefsFailed(results)) {
-    RecordMigrationResult(false);
-    return;
-  }
-
-  migration_finished_callback_ =
-      base::BarrierCallback<PasswordManagerSettingGmsAccessResult>(
-          2,
-          base::BindOnce(&PasswordManagerSettingsServiceAndroidMigrationImpl::
-                             FinishSettingsMigration,
-                         weak_ptr_factory_.GetWeakPtr()));
-
-  for (auto setting : kMigratablePasswordSettings) {
-    const PrefService::Preference* regular_pref =
-        GetRegularPrefFromSetting(pref_service_, setting);
-    const PrefService::Preference* android_pref =
-        GetGMSPrefFromSetting(pref_service_, setting);
-
-    if (regular_pref->IsDefaultValue()) {
-      // If Chrome had default value then value from gms is saved to Chrome.
-      pref_service_->SetBoolean(regular_pref->name(),
-                                android_pref->GetValue()->GetBool());
-      // Migraion will finish only if this callback is called twice, but in this
-      // case we didn't call gms, so we can mark this setting manually as
-      // successfully migrated.
-      migration_finished_callback_.Run(PasswordManagerSettingGmsAccessResult(
-          setting, /*was_successful=*/true));
-      continue;
-    }
-
-    if (android_pref->GetValue()->GetBool() ==
-        pref_service_->GetDefaultPrefValue(android_pref->name())->GetBool()) {
-      // If Chrome had user set pref value and gms had default value, then
-      // Chrome value is saved in gms.
-      bridge_helper_->SetPasswordSettingValue(
-          std::nullopt, setting, regular_pref->GetValue()->GetBool());
-      pref_service_->SetBoolean(android_pref->name(),
-                                regular_pref->GetValue()->GetBool());
-      continue;
-    }
-
-    // If Chrome had user set pref value and gms had non default value, then
-    // the most conservative value is saved. Meaning that if either one of
-    // them, had this setting disabled, it should be disabled after the
-    // migration.
-    bool conservative_value = regular_pref->GetValue()->GetBool() &&
-                              android_pref->GetValue()->GetBool();
-    bridge_helper_->SetPasswordSettingValue(std::nullopt, setting,
-                                            conservative_value);
-    pref_service_->SetBoolean(android_pref->name(), conservative_value);
-    pref_service_->SetBoolean(regular_pref->name(), conservative_value);
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImpl::
-    FinishSettingsMigration(
-        const std::vector<PasswordManagerSettingGmsAccessResult>& results) {
-  migration_finished_callback_.Reset();
-  // Check if setting settings prefs failed.
-  if (DidAccessingGMSPrefsFailed(results)) {
-    RecordMigrationResult(false);
-    return;
-  }
-
-  RecordMigrationResult(true);
-  pref_service_->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-}
diff --git a/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.h b/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.h
deleted file mode 100644
index 75c06069..0000000
--- a/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_MANAGER_SETTINGS_SERVICE_ANDROID_MIGRATION_IMPL_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_MANAGER_SETTINGS_SERVICE_ANDROID_MIGRATION_IMPL_H_
-
-#include <memory>
-
-#include "base/containers/flat_set.h"
-#include "base/memory/raw_ptr.h"
-#include "base/types/pass_key.h"
-#include "chrome/browser/password_manager/android/password_manager_lifecycle_helper.h"
-#include "chrome/browser/password_manager/android/password_settings_updater_android_bridge_helper.h"
-#include "chrome/browser/password_manager/android/password_settings_updater_android_receiver_bridge.h"
-#include "components/password_manager/core/browser/password_manager_settings_service.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/sync/service/sync_service.h"
-
-class PrefService;
-
-struct PasswordManagerSettingGmsAccessResult {
-  password_manager::PasswordManagerSetting setting;
-  bool was_successful;
-};
-
-// Service implementation responsible with requesting and updating settings
-// prefs based on settings changes in Google Mobile Services. It also answers
-// password manager prefs queries, taking into account managed prefs and
-// the possibility of communicating with GMS.
-// This service performs migrations and fallbacks to prior versions of
-// the password manager. It should only be used during the mgiration phase.
-// TODO(crbug.com/394547508): Remove this once the login DB and the old
-// password manager are deprecated.
-class PasswordManagerSettingsServiceAndroidMigrationImpl
-    : public password_manager::PasswordManagerSettingsService,
-      public password_manager::PasswordSettingsUpdaterAndroidReceiverBridge::
-          Consumer,
-      public syncer::SyncServiceObserver {
- public:
-  PasswordManagerSettingsServiceAndroidMigrationImpl(
-      PrefService* pref_service,
-      syncer::SyncService* sync_service);
-  PasswordManagerSettingsServiceAndroidMigrationImpl(
-      base::PassKey<
-          class PasswordManagerSettingsServiceAndroidMigrationImplBaseTest>,
-      PrefService* pref_service,
-      syncer::SyncService* sync_service,
-      std::unique_ptr<
-          password_manager::PasswordSettingsUpdaterAndroidBridgeHelper>
-          bridge_helper,
-      std::unique_ptr<PasswordManagerLifecycleHelper> lifecycle_helper);
-
-  PasswordManagerSettingsServiceAndroidMigrationImpl(
-      const PasswordManagerSettingsServiceAndroidMigrationImpl&) = delete;
-  PasswordManagerSettingsServiceAndroidMigrationImpl(
-      PasswordManagerSettingsServiceAndroidMigrationImpl&&) = delete;
-  PasswordManagerSettingsServiceAndroidMigrationImpl& operator=(
-      const PasswordManagerSettingsServiceAndroidMigrationImpl&) = delete;
-  PasswordManagerSettingsServiceAndroidMigrationImpl& operator=(
-      const PasswordManagerSettingsServiceAndroidMigrationImpl&&) = delete;
-
-  ~PasswordManagerSettingsServiceAndroidMigrationImpl() override;
-
-  // PasswordManagerSettingsService implementation
-  bool IsSettingEnabled(
-      password_manager::PasswordManagerSetting setting) const override;
-  void RequestSettingsFromBackend() override;
-  void TurnOffAutoSignIn() override;
-
- private:
-  // Does actions that need to be done on startup (e.g. attaches services
-  // observers and migrates and requests settings if needed).
-  void Init();
-
-  void OnChromeForegrounded();
-
-  // PasswordSettingsUpdaterAndroidBridgeHelper::Consumer implementation
-  void OnSettingValueFetched(password_manager::PasswordManagerSetting setting,
-                             bool value) override;
-  void OnSettingValueAbsent(
-      password_manager::PasswordManagerSetting setting) override;
-  void OnSettingFetchingError(
-      password_manager::PasswordManagerSetting setting,
-      AndroidBackendAPIErrorCode api_error_code) override;
-  void OnSuccessfulSettingChange(
-      password_manager::PasswordManagerSetting setting) override;
-  void OnFailedSettingChange(
-      password_manager::PasswordManagerSetting setting,
-      AndroidBackendAPIErrorCode api_error_code) override;
-
-  // Stores the given `value` of the `setting` into the android-only GMS prefs.
-  // Stores the same `value` in the old prefs are not being synced.
-  // If the `value` is not given, the prefs will be set to default.
-  void WriteToTheCacheAndRegularPref(
-      password_manager::PasswordManagerSetting setting,
-      std::optional<bool> value);
-
-  // syncer::SyncServiceObserver implementation
-  void OnStateChanged(syncer::SyncService* sync) override;
-
-  // Updates information about the current setting fetch after receiving
-  // a reply from the backend.
-  void UpdateSettingFetchState(
-      password_manager::PasswordManagerSetting received_setting);
-
-  // Asynchronously fetches settings from backend regardless of sync status.
-  void FetchSettings();
-
-  // Migrates settings to GMS Core if the user is reenrolled into the UPM
-  // in the middle of the browser session.
-  void OnUnenrollmentPreferenceChanged();
-
-  // Checks that the user is either syncing and enrolled in UPM or not syncing
-  // and ready to use local UPM.
-  bool UsesUPMBackend() const;
-
-  // Checks for the settings migration requirements. It goes through every
-  // setting pref and resolves differences between value in Chrome and GMS.
-  // This method will be run for upm users with and without local passwords
-  // support. For the former ones this should be a noop without any changes to
-  // their prefs. For the latter ones pref values might change.
-  void MigratePrefsIfNeeded(
-      const std::vector<PasswordManagerSettingGmsAccessResult>& results);
-
-  // Checks if setting prefs was successful and marks the migation as complete
-  // if there were no errors.
-  void FinishSettingsMigration(
-      const std::vector<PasswordManagerSettingGmsAccessResult>& results);
-
-  // Pref service used to read and write password manager user prefs.
-  raw_ptr<PrefService> pref_service_ = nullptr;
-
-  // An observer for the pref service.
-  PrefChangeRegistrar pref_change_registrar_;
-
-  // Sync service used to check whether the user has chosen to sync passwords
-  // or settings.
-  raw_ptr<syncer::SyncService> sync_service_ = nullptr;
-
-  // Bridge helper used by the service to communicate with the Java backend.
-  std::unique_ptr<password_manager::PasswordSettingsUpdaterAndroidBridgeHelper>
-      bridge_helper_;
-
-  // Notifies the service when Chrome is foregrounded, so that the service
-  // can request settings values from Google Mobile Services.
-  std::unique_ptr<PasswordManagerLifecycleHelper> lifecycle_helper_;
-
-  // Cached value of the password sync setting.
-  bool is_password_sync_enabled_ = false;
-
-  // True if settings were requested from the backend after password sync
-  // setting was changed, and the fetch is still in progress.
-  bool fetch_after_sync_status_change_in_progress_ = false;
-
-  // Tires to start migration after getting prefs from gms finished.
-  // This callback needs to be run even if getting pref value from GMS failed,
-  // because of the following scenario:
-  // 1. Chrome is opened, fetching prefs has started.
-  // 2. One of the calls to GMS fails, the other succeeds.
-  // 3. Chrome is put to the background and then to the foreground again.
-  // 4. That causes fetching prefs from the GMS again. And if one of them fails
-  // and the other succeeds, we would count the migration as successful. By
-  // calling the `start_migration_callback_` with was_successful set to false we
-  // ensure that if anything failed, migration will be counted as failed.
-  base::RepeatingCallback<void(PasswordManagerSettingGmsAccessResult)>
-      start_migration_callback_;
-
-  // Finishes migration and checks for errors.
-  base::RepeatingCallback<void(PasswordManagerSettingGmsAccessResult)>
-      migration_finished_callback_;
-
-  // Settings requested from the backend after a sync status change, but not
-  // fetched yet.
-  base::flat_set<password_manager::PasswordManagerSetting> awaited_settings_;
-
-  base::WeakPtrFactory<PasswordManagerSettingsServiceAndroidMigrationImpl>
-      weak_ptr_factory_{this};
-};
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_MANAGER_SETTINGS_SERVICE_ANDROID_MIGRATION_IMPL_H_
diff --git a/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl_unittest.cc b/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl_unittest.cc
deleted file mode 100644
index 09938d52..0000000
--- a/chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl_unittest.cc
+++ /dev/null
@@ -1,2001 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.h"
-
-#include <memory>
-#include <optional>
-
-#include "base/feature_list.h"
-#include "base/memory/weak_ptr.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/password_manager/android/fake_password_manager_lifecycle_helper.h"
-#include "chrome/browser/password_manager/android/password_settings_updater_android_bridge_helper.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_manager_setting.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/public/base/signin_pref_names.h"
-#include "components/sync/base/user_selectable_type.h"
-#include "components/sync/service/sync_user_settings.h"
-#include "components/sync/test/test_sync_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-using password_manager::FakePasswordManagerLifecycleHelper;
-using password_manager::PasswordManagerSetting;
-using password_manager::PasswordSettingsUpdaterAndroidBridgeHelper;
-using Consumer =
-    password_manager::PasswordSettingsUpdaterAndroidReceiverBridge::Consumer;
-using SyncingAccount = password_manager::
-    PasswordSettingsUpdaterAndroidReceiverBridge::SyncingAccount;
-using testing::_;
-using testing::Eq;
-
-const char kTestAccount[] = "testaccount@gmail.com";
-
-class MockPasswordSettingsUpdaterBridgeHelper
-    : public PasswordSettingsUpdaterAndroidBridgeHelper {
- public:
-  MOCK_METHOD(void, SetConsumer, (base::WeakPtr<Consumer>), (override));
-  MOCK_METHOD(void,
-              GetPasswordSettingValue,
-              (std::optional<SyncingAccount>, PasswordManagerSetting),
-              (override));
-  MOCK_METHOD(void,
-              SetPasswordSettingValue,
-              (std::optional<SyncingAccount>, PasswordManagerSetting, bool),
-              (override));
-};
-
-}  // namespace
-
-class PasswordManagerSettingsServiceAndroidMigrationImplBaseTest
-    : public testing::Test {
- protected:
-  PasswordManagerSettingsServiceAndroidMigrationImplBaseTest();
-  ~PasswordManagerSettingsServiceAndroidMigrationImplBaseTest() override;
-
-  void InitializeSettingsService(bool password_sync_enabled,
-                                 bool setting_sync_enabled);
-
-  std::unique_ptr<PasswordManagerSettingsServiceAndroidMigrationImpl>
-  CreateNewService(
-      std::unique_ptr<MockPasswordSettingsUpdaterBridgeHelper> bridge_helper);
-
-  void SetPasswordsSync(bool enabled);
-  void SetSettingsSync(bool enabled);
-
-  void ExpectSettingsRetrievalFromBackend(std::optional<SyncingAccount> account,
-                                          size_t times);
-
-  void ExpectSettingsRetrievalFromBackend();
-
-  Consumer* updater_bridge_consumer() { return settings_service_.get(); }
-  password_manager::PasswordManagerSettingsService* settings_service() {
-    return settings_service_.get();
-  }
-  TestingPrefServiceSimple* pref_service() { return &test_pref_service_; }
-  syncer::TestSyncService* sync_service() { return &test_sync_service_; }
-  FakePasswordManagerLifecycleHelper* lifecycle_helper() {
-    return fake_lifecycle_helper_;
-  }
-  MockPasswordSettingsUpdaterBridgeHelper* bridge_helper() {
-    return mock_bridge_helper_;
-  }
-  base::HistogramTester* histogram_tester() { return &histogram_tester_; }
-
- private:
-  void RegisterPrefs();
-
-  TestingPrefServiceSimple test_pref_service_;
-  std::unique_ptr<PasswordManagerSettingsServiceAndroidMigrationImpl>
-      settings_service_;
-  syncer::TestSyncService test_sync_service_;
-  raw_ptr<MockPasswordSettingsUpdaterBridgeHelper> mock_bridge_helper_ =
-      nullptr;
-  raw_ptr<FakePasswordManagerLifecycleHelper> fake_lifecycle_helper_ = nullptr;
-  base::HistogramTester histogram_tester_;
-};
-
-PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    PasswordManagerSettingsServiceAndroidMigrationImplBaseTest() {
-  RegisterPrefs();
-  CoreAccountInfo sync_account_info;
-  sync_account_info.email = kTestAccount;
-  test_sync_service_.SetSignedIn(signin::ConsentLevel::kSync,
-                                 sync_account_info);
-}
-
-PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    ~PasswordManagerSettingsServiceAndroidMigrationImplBaseTest() {
-  testing::Mock::VerifyAndClearExpectations(mock_bridge_helper_);
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    InitializeSettingsService(bool password_sync_enabled,
-                              bool setting_sync_enabled) {
-  std::unique_ptr<MockPasswordSettingsUpdaterBridgeHelper> bridge_helper =
-      std::make_unique<MockPasswordSettingsUpdaterBridgeHelper>();
-  mock_bridge_helper_ = bridge_helper.get();
-
-  EXPECT_CALL(*mock_bridge_helper_, SetConsumer);
-
-  std::unique_ptr<FakePasswordManagerLifecycleHelper> lifecycle_helper =
-      std::make_unique<FakePasswordManagerLifecycleHelper>();
-  fake_lifecycle_helper_ = lifecycle_helper.get();
-
-  SetPasswordsSync(password_sync_enabled);
-  SetSettingsSync(setting_sync_enabled);
-  settings_service_ = std::make_unique<
-      PasswordManagerSettingsServiceAndroidMigrationImpl>(
-      base::PassKey<
-          class PasswordManagerSettingsServiceAndroidMigrationImplBaseTest>(),
-      &test_pref_service_, &test_sync_service_, std::move(bridge_helper),
-      std::move(lifecycle_helper));
-}
-
-std::unique_ptr<PasswordManagerSettingsServiceAndroidMigrationImpl>
-PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::CreateNewService(
-    std::unique_ptr<MockPasswordSettingsUpdaterBridgeHelper> bridge_helper =
-        nullptr) {
-  if (!bridge_helper) {
-    bridge_helper = std::make_unique<MockPasswordSettingsUpdaterBridgeHelper>();
-  }
-  std::unique_ptr<FakePasswordManagerLifecycleHelper> lifecycle_helper =
-      std::make_unique<FakePasswordManagerLifecycleHelper>();
-  return std::make_unique<PasswordManagerSettingsServiceAndroidMigrationImpl>(
-      base::PassKey<
-          class PasswordManagerSettingsServiceAndroidMigrationImplBaseTest>(),
-      pref_service(), sync_service(), std::move(bridge_helper),
-      std::move(lifecycle_helper));
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    SetPasswordsSync(bool enabled) {
-  syncer::UserSelectableTypeSet selected_sync_types =
-      test_sync_service_.GetUserSettings()->GetSelectedTypes();
-  if (enabled) {
-    selected_sync_types.Put(syncer::UserSelectableType::kPasswords);
-  } else {
-    selected_sync_types.Remove(syncer::UserSelectableType::kPasswords);
-  }
-  test_sync_service_.GetUserSettings()->SetSelectedTypes(false,
-                                                         selected_sync_types);
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    SetSettingsSync(bool enabled) {
-  syncer::UserSelectableTypeSet selected_sync_types =
-      test_sync_service_.GetUserSettings()->GetSelectedTypes();
-  if (enabled) {
-    selected_sync_types.Put(syncer::UserSelectableType::kPreferences);
-  } else {
-    selected_sync_types.Remove(syncer::UserSelectableType::kPreferences);
-  }
-  test_sync_service_.GetUserSettings()->SetSelectedTypes(false,
-                                                         selected_sync_types);
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    ExpectSettingsRetrievalFromBackend(std::optional<SyncingAccount> account,
-                                       size_t times) {
-  EXPECT_CALL(
-      *bridge_helper(),
-      GetPasswordSettingValue(
-          Eq(account), Eq(PasswordManagerSetting::kOfferToSavePasswords)))
-      .Times(times);
-  EXPECT_CALL(*bridge_helper(),
-              GetPasswordSettingValue(Eq(account),
-                                      Eq(PasswordManagerSetting::kAutoSignIn)))
-      .Times(times);
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kBiometricTouchToFill)) {
-    EXPECT_CALL(
-        *bridge_helper(),
-        GetPasswordSettingValue(
-            Eq(account),
-            Eq(PasswordManagerSetting::kBiometricReauthBeforePwdFilling)))
-        .Times(times);
-  }
-}
-
-void PasswordManagerSettingsServiceAndroidMigrationImplBaseTest::
-    RegisterPrefs() {
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kCredentialsEnableService, true);
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kCredentialsEnableAutosignin, true);
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, true);
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kAutoSignInEnabledGMS, true);
-  test_pref_service_.registry()->RegisterStringPref(
-      ::prefs::kGoogleServicesLastSyncingUsername, kTestAccount);
-  test_pref_service_.registry()->RegisterStringPref(
-      ::prefs::kGoogleServicesLastSignedInUsername, kTestAccount);
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      false);
-  test_pref_service_.registry()->RegisterIntegerPref(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, false);
-  test_pref_service_.registry()->RegisterBooleanPref(
-      password_manager::prefs::kEmptyProfileStoreLoginDatabase, false);
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kBiometricTouchToFill)) {
-    test_pref_service_.registry()->RegisterBooleanPref(
-        password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);
-  }
-}
-
-// This suite starts with the pref `kPasswordsUseUPMLocalAndSeparateStores` off.
-class PasswordManagerSettingsServiceAndroidMigrationImplTest
-    : public PasswordManagerSettingsServiceAndroidMigrationImplBaseTest {};
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       DoesntRequestSettingsOnServiceCreation) {
-  std::unique_ptr<MockPasswordSettingsUpdaterBridgeHelper> bridge_helper =
-      std::make_unique<MockPasswordSettingsUpdaterBridgeHelper>();
-
-  ASSERT_NE(bridge_helper, nullptr);
-
-  // The settings shouldn't be requested upon creating the service, which
-  // happens on startup, because Chrome also gets foregrounded and settings are
-  // requested on Chrome foregrounding.
-  EXPECT_CALL(*bridge_helper,
-              GetPasswordSettingValue(
-                  Eq(SyncingAccount(kTestAccount)),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords)))
-      .Times(0);
-  EXPECT_CALL(*bridge_helper,
-              GetPasswordSettingValue(Eq(SyncingAccount(kTestAccount)),
-                                      Eq(PasswordManagerSetting::kAutoSignIn)))
-      .Times(0);
-
-  SetPasswordsSync(true);
-  CreateNewService(std::move(bridge_helper));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingFetchSyncingBoth) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingFetchNotSyncingSettings) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingFetchNotSyncingPasswords) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInSettingFetchSyncingBoth) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, /*value=*/false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInFetchNotSyncingSettings) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, /*value=*/false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInFetchNotSyncingPasswords) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, /*value=*/false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingAbsentDefaultSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue(_, _, _)).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingAbsentDoesntSetValueSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(false));
-  // The settings for syncing users should no longer be written to GMSCore.
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  Eq(SyncingAccount(kTestAccount)),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords), false))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingAbsentSetValueNotSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(false));
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue(_, _, _)).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnSaveSettingAbsentUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(false));
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue(_, _, _)).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInAbsentDefaultSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue(_, _, _)).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInAbsentDontSetValueSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(false));
-
-  // The settings for syncing users should no longer be written to GmsCore.
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(SyncingAccount(kTestAccount)),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInAbsentSetValueNotSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(false));
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue(_, _, _)).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       OnAutoSignInAbsentSetValueUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(false));
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue(_, _, _)).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-}
-
-// Checks that general syncable prefs are dumped into the android-only GMS
-// prefs before settings are requested when sync is enabled.
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       PasswordSyncEnablingDoesntMovePrefs) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(false));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableAutosignin,
-      base::Value(false));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  SetPasswordsSync(/*enabled=*/true);
-  sync_service()->FireStateChanged();
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-// Checks that general syncable prefs are dumped into the android-only GMS
-// prefs before settings are requested when sync is enabled.
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       PasswordSyncEnablingPrefsUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(false));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableAutosignin,
-      base::Value(false));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  SetPasswordsSync(/*enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-  sync_service()->FireStateChanged();
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       PasswordSyncEnablingGMSSettingAbsentChromeHasUserSetting) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  pref_service()->SetBoolean(password_manager::prefs::kAutoSignInEnabledGMS,
-                             false);
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  SetPasswordsSync(/*enabled=*/true);
-  sync_service()->FireStateChanged();
-
-  // For a syncing user, the setting stored in the account takes precedence and
-  // overwrites the local setting, even if the account setting has a default
-  // value.
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kCredentialsEnableAutosignin),
-            nullptr);
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kAutoSignInEnabledGMS),
-            nullptr);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       PasswordSyncEnablingGMSHasSetting) {
-  // TODO(crbug.com/40286015): Split this test.
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  SetPasswordsSync(/*enabled=*/true);
-  sync_service()->FireStateChanged();
-
-  // If the local setting in Chrome differs from the setting stored in the
-  // account, the account setting is stored in prefs and used.
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       PasswordSyncDisablingGMSSettingAbsent) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  pref_service()->SetBoolean(password_manager::prefs::kAutoSignInEnabledGMS,
-                             false);
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  SetPasswordsSync(/*enabled=*/false);
-  sync_service()->FireStateChanged();
-
-  // Settings shouldn't be written to GMS Core.
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       PasswordSyncDisablingGMSHasSetting) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  SetPasswordsSync(/*enabled=*/false);
-  sync_service()->FireStateChanged();
-
-  // If the setting in Chrome differs from the setting in GMS Core, GMS Core
-  // setting is stored in prefs and used.
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SavePasswordsSettingNotSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(true));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(false));
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SavePasswordsSettingSyncingManaged) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetManagedPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(false));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(true));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SavePasswordsSettingSyncingNotManaged) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(true));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(false));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SavePasswordsSettingUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(true));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(false));
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       AutoSignInSettingNotSyncing) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableAutosignin, base::Value(true));
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(false));
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       AutoSignInSettingSyncingManaged) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetManagedPref(
-      password_manager::prefs::kCredentialsEnableAutosignin,
-      base::Value(false));
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(true));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       AutoSignInSettingSyncingNotManaged) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableAutosignin, base::Value(true));
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(false));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       AutoSignInSettingUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  pref_service()->SetUserPref(
-      password_manager::prefs::kCredentialsEnableAutosignin, base::Value(true));
-  pref_service()->SetUserPref(password_manager::prefs::kAutoSignInEnabledGMS,
-                              base::Value(false));
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SettingsAreRequestedFromBackendWhenPasswordSyncEnabled) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  settings_service()->RequestSettingsFromBackend();
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SettingsAreNotRequestedFromBackendWhenPasswordSyncDisabled) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/0);
-  settings_service()->RequestSettingsFromBackend();
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       SettingsAreNotRequestedFromBackendWhenUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/0);
-  settings_service()->RequestSettingsFromBackend();
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       TurnOffAutoSignInNotSyncingPasswords) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  settings_service()->TurnOffAutoSignIn();
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       TurnOffAutoSignInSyncingPasswordsNotPrefs) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(SyncingAccount(kTestAccount)),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false))
-      .Times(1);
-  settings_service()->TurnOffAutoSignIn();
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       TurnOffAutoSignInSyncingPasswordsAndPrefs) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(SyncingAccount(kTestAccount)),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false))
-      .Times(1);
-  settings_service()->TurnOffAutoSignIn();
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       TurnOffAutoSignInSyncingUserUnenrolledFromUPM) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  settings_service()->TurnOffAutoSignIn();
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       TestDontMigrateSettingsOnReenrollingIntoUPM) {
-  SetPasswordsSync(true);
-
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  // Set an explicit value on the "Offer to save passwords" pref.
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-
-  // Imitate reenrolment into UPM and triggering settings migration.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kAutoSignInEnabledGMS),
-            nullptr);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTest,
-       UnenrollmentPreventsRequestsOnSyncTurningOff) {
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-
-  // Since the user was unenrolled and they don't have local backend support, it
-  // means that the backend is unreachable and instead the regular prefs are
-  // used, so there shouldn't be any backend request.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount), /*times=*/0);
-  SetPasswordsSync(/*enabled=*/false);
-  sync_service()->FireStateChanged();
-}
-
-// This suite starts with the pref `kPasswordsUseUPMLocalAndSeparateStores` on.
-class PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers
-    : public PasswordManagerSettingsServiceAndroidMigrationImplBaseTest {
- protected:
-  PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers() {
-    pref_service()->SetInteger(
-        password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
-  }
-};
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       RespectsPolicyDespiteErrorOverrideForLocalBackend) {
-  // This test checks that the managed pref has a priority over the manually set
-  // values and that the password saving isn't suspended for users who are not
-  // syncing passwords.
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, false);
-
-  pref_service()->SetManagedPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(true));
-
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       UnenrollmentDoesntPreventUPMLocalRequests) {
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  lifecycle_helper()->OnForegroundSessionStart();
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       UnenrollmentDoesntPreventUPMLocalOnSettingValueAbsent) {
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue).Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kCredentialsEnableAutosignin),
-            nullptr);
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kAutoSignInEnabledGMS),
-            nullptr);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       UnenrollmentDoesntPreventUPMLocalOnSettingValueFetched) {
-  pref_service()->SetBoolean(
-      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-      true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(*bridge_helper(), SetPasswordSettingValue).Times(0);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetUserPrefValue(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetUserPrefValue(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       OnSaveSettingFetchUpdatesTheCacheAndRegularPref) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       OnSaveSettingFetchUpdatesOnlyTheCache) {
-  // This test is similar to OnSaveSettingFetchUpdatesTheCacheAndRegularPref,
-  // but it shows that the regular pref is not updated if settings sync is on,
-  // in order to prevent sync cycles.
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       OnSettingsAbsentUpdatesTheGMSAndRegularPref) {
-  // This test covers the case when the cache has a non-default value and GMS
-  // has a default value. The user can have non-default values in the cache
-  // while they're not yet syncing. When they start syncing, the cache will be
-  // overwritten by the value read from GMSCore, which could now be default,
-  // since it's now read from the storage for the account.
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, false);
-
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kOfferToSavePasswordsEnabledGMS),
-            nullptr);
-  // The regular pref also needs to be overwritten because the user might drop
-  // out of the enabled group and will use the regular pref again.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kCredentialsEnableService),
-            nullptr);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       OnSettingsAbsentUpdatesOnlyTheGMSPref) {
-  // This test is similar to OnSettingsAbsentUpdatesTheGMSAndRegularPref, but
-  // it shows that the regular pref is not updated if settings sync is on, in
-  // order to prevent sync cycles.
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, false);
-
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kOfferToSavePasswordsEnabledGMS),
-            nullptr);
-  // The regular pref should not be overwritten because settings are synced.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       IsSettingEnabledChecksGMSPrefWhenSettingsMigratedToUPMLocal) {
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  pref_service()->SetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, false);
-
-  // The settings migration happened so the setting from CMS Core is used.
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       RequestSettingsFromBackendFetchesSettings) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-
-  settings_service()->RequestSettingsFromBackend();
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       TurnOffAutoSignInWhenNotSyncingSettingsChangesTheGMSPrefAndRegularPref) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(std::nullopt),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false));
-
-  settings_service()->TurnOffAutoSignIn();
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       TurnOffAutoSignInWhenSyncingSettingsChangesOnlyTheGMSPref) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/true);
-
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  settings_service()->TurnOffAutoSignIn();
-
-  // The regular pref should not be updated because settings are synced.
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       PasswordSyncDisablingGMSSettingAbsent) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  SetPasswordsSync(/*enabled=*/false);
-  sync_service()->FireStateChanged();
-
-  // Settings shouldn't be written to GMS Core.
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kCredentialsEnableAutosignin),
-            nullptr);
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kAutoSignInEnabledGMS),
-            nullptr);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       PasswordSyncDisablingGMSHasSetting) {
-  InitializeSettingsService(/*password_sync_enabled=*/true,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  SetPasswordsSync(/*enabled=*/false);
-  sync_service()->FireStateChanged();
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       PasswordSyncEnablingGMSSettingAbsent) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  SetPasswordsSync(/*enabled=*/true);
-  sync_service()->FireStateChanged();
-
-  // Settings shouldn't be written to GMS Core.
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kCredentialsEnableAutosignin),
-            nullptr);
-  EXPECT_EQ(pref_service()->GetUserPrefValue(
-                password_manager::prefs::kAutoSignInEnabledGMS),
-            nullptr);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       PasswordSyncEnablingGMSHasSetting) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  // Settings should be requested from GMS Core on sync state change.
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount),
-                                     /*times=*/1);
-  SetPasswordsSync(/*enabled=*/true);
-  sync_service()->FireStateChanged();
-
-  // Settings shouldn't be written to GMS Core.
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, /*value=*/false);
-
-  // The old Chrome pref is also updated, because settings sync is off, so there
-  // is no risk of sync cycles.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       DoesntRequestSettingsOnServiceCreation) {
-  std::unique_ptr<MockPasswordSettingsUpdaterBridgeHelper> bridge_helper =
-      std::make_unique<MockPasswordSettingsUpdaterBridgeHelper>();
-
-  ASSERT_NE(bridge_helper, nullptr);
-
-  // The settings shouldn't be requested upon creating the service, which
-  // happens on startup, because Chrome also gets foregrounded and settings are
-  // requested on Chrome foregrounding.
-  EXPECT_CALL(*bridge_helper,
-              GetPasswordSettingValue(
-                  Eq(SyncingAccount(kTestAccount)),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords)))
-      .Times(0);
-  EXPECT_CALL(*bridge_helper,
-              GetPasswordSettingValue(Eq(SyncingAccount(kTestAccount)),
-                                      Eq(PasswordManagerSetting::kAutoSignIn)))
-      .Times(0);
-
-  SetPasswordsSync(false);
-  CreateNewService(std::move(bridge_helper));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       SavePasswordsSettingManagedByCustodian) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetSupervisedUserPref(
-      password_manager::prefs::kCredentialsEnableService, base::Value(false));
-  pref_service()->SetUserPref(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS,
-      base::Value(true));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsChromeHadNonDefaultValueGmsHadDefaultValue) {
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(std::nullopt),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false));
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  Eq(std::nullopt),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords), false));
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, true);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, true);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  updater_bridge_consumer()->OnSuccessfulSettingChange(
-      PasswordManagerSetting::kAutoSignIn);
-  updater_bridge_consumer()->OnSuccessfulSettingChange(
-      PasswordManagerSetting::kOfferToSavePasswords);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsChromeAndGmsHadNonDefaultValue) {
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, false);
-  pref_service()->SetBoolean(password_manager::prefs::kAutoSignInEnabledGMS,
-                             false);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(std::nullopt),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false));
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  Eq(std::nullopt),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords), false));
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, false);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, false);
-
-  updater_bridge_consumer()->OnSuccessfulSettingChange(
-      PasswordManagerSetting::kAutoSignIn);
-  updater_bridge_consumer()->OnSuccessfulSettingChange(
-      PasswordManagerSetting::kOfferToSavePasswords);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       SettingsMigrationNotStartedIfCompletedBefore) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  Eq(std::nullopt),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  Eq(std::nullopt), Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, /*value=*/false);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, /*value=*/false);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsChromeAndGMSHadDefaultValue) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kAutoSignIn);
-  updater_bridge_consumer()->OnSettingValueAbsent(
-      PasswordManagerSetting::kOfferToSavePasswords);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrationCallbackNotCreatedWhenChromeAndGMSHadDefaultValue) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  // The Chrome settings were default, so the migration is marked as done.
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-
-  // If the migration callback would have been created, despite the migration
-  // being marked as done, the following fetching errors would have been
-  // recorded in histograms. This is the only possible way to test if the
-  // callback was unnecessarily created because it can't be accessed directly
-  // and there are no mocks that would be related to the callback that can be
-  // tested to verify if the callback was created.
-  updater_bridge_consumer()->OnSettingFetchingError(
-      PasswordManagerSetting::kAutoSignIn,
-      AndroidBackendAPIErrorCode::kUnexpectedError);
-  updater_bridge_consumer()->OnSettingFetchingError(
-      PasswordManagerSetting::kOfferToSavePasswords,
-      AndroidBackendAPIErrorCode::kUnexpectedError);
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-  histogram_tester()->ExpectBucketCount(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", false, 0);
-  histogram_tester()->ExpectBucketCount(
-      "PasswordManager.PasswordSettingsMigrationFailed.AutoSignIn.APIError2",
-      AndroidBackendAPIErrorCode::kUnexpectedError, 0);
-  histogram_tester()->ExpectBucketCount(
-      "PasswordManager.PasswordSettingsMigrationFailed.OfferToSavePasswords."
-      "APIError2",
-      AndroidBackendAPIErrorCode::kUnexpectedError, 0);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       SettingsMigrationNotPerformedWhenInterruptedByTurningOnSync) {
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-
-  // The responses from GMS Core didn't yet come so the migration doesn't happen
-  // yet.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  ExpectSettingsRetrievalFromBackend(SyncingAccount(kTestAccount), /*times=*/1);
-  SetPasswordsSync(true);
-  sync_service()->FireStateChanged();
-
-  // The local settings migraton should not be performed, even though these
-  // calls will try to start it, because the user is syncing now.
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, false);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 0);
-  histogram_tester()->ExpectBucketCount(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", false, 0);
-}
-
-// Checks if settings migration happens only once per browser lifetime.
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsChromePutToForegroundTwice) {
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/2);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, true);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, true);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  // Chrome gets put to the background and to the foreground again.
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, false);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-}
-
-// Checks that the migration algorithm determines what to do for each setting
-// independently from the other.
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsEachPrefHadDifferentValue) {
-  // User has changed one setting.
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(std::nullopt),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false));
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  // GMS also had one setting changed, but it is different than the one in
-  // Chrome.
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, true);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  updater_bridge_consumer()->OnSuccessfulSettingChange(
-      PasswordManagerSetting::kAutoSignIn);
-
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsGettingValueFailed) {
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, true);
-
-  // The cached values are true until settings get fetched from GMS Core.
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  ASSERT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  // Fetching the auto sign in setting fails.
-  updater_bridge_consumer()->OnSettingFetchingError(
-      PasswordManagerSetting::kAutoSignIn,
-      AndroidBackendAPIErrorCode::kUnexpectedError);
-  // Fetching the offer to save passwords setting succeeds and is different than
-  // the value in the Chrome setting.
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, true);
-
-  // Old Chrome settings stay intact.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-
-  // The Cached GMS values in Chrome get updated on a successful fetch so offer
-  // to save passwords is now false.
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kAutoSignInEnabledGMS));
-
-  // The Chrome values get returned if the migration failed.
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-  EXPECT_TRUE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-
-  // Settings migration wasn't successful.
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationFailed.AutoSignIn.APIError2",
-      AndroidBackendAPIErrorCode::kUnexpectedError, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", false, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsMarkedAsDoneIfChromeHadDefaultPrefs) {
-  pref_service()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", true, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrationNotDoneIfDefaultSettingsButNoStoreSplit) {
-  pref_service()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-
-  histogram_tester()->ExpectTotalCount(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", 0);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsGotValueForTheSamePrefTwice) {
-  // Set prefs to user selected value so that the migration is triggered
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  _, Eq(PasswordManagerSetting::kOfferToSavePasswords), _))
-      .Times(0);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(_, Eq(PasswordManagerSetting::kAutoSignIn), _))
-      .Times(0);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, false);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableService));
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin));
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", false, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       DefaultSettingsMigrationResetsIfLocalPwdMigrationOff) {
-  pref_service()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  // Setting the settings migration pref to true to mimic the case when it was
-  // incorrectly set to true.
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       DefaultSettingsMigrationDoesntResetIfLocalPwdMigrationPending) {
-  pref_service()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-              kOffAndMigrationPending));
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  // Setting the settings migration pref to true to mimic the case when it was
-  // already set to true.
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       DefaultSettingsMigrationDoesntResetIfLocalPwdMigrationOn) {
-  pref_service()->SetInteger(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
-  pref_service()->ClearPref(password_manager::prefs::kCredentialsEnableService);
-  pref_service()->ClearPref(
-      password_manager::prefs::kCredentialsEnableAutosignin);
-
-  // Setting the settings migration pref to true to mimic the case when it was
-  // already set to true.
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
-
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  EXPECT_TRUE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       MigrateSettingsSettingGmsPrefFailed) {
-  pref_service()->SetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal, false);
-  pref_service()->SetBoolean(password_manager::prefs::kCredentialsEnableService,
-                             false);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kCredentialsEnableAutosignin, false);
-  pref_service()->SetBoolean(password_manager::prefs::kAutoSignInEnabledGMS,
-                             true);
-  pref_service()->SetBoolean(
-      password_manager::prefs::kOfferToSavePasswordsEnabledGMS, true);
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  EXPECT_CALL(
-      *bridge_helper(),
-      SetPasswordSettingValue(Eq(std::nullopt),
-                              Eq(PasswordManagerSetting::kAutoSignIn), false));
-  EXPECT_CALL(*bridge_helper(),
-              SetPasswordSettingValue(
-                  Eq(std::nullopt),
-                  Eq(PasswordManagerSetting::kOfferToSavePasswords), false));
-  lifecycle_helper()->OnForegroundSessionStart();
-
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kAutoSignIn, true);
-  updater_bridge_consumer()->OnSettingValueFetched(
-      PasswordManagerSetting::kOfferToSavePasswords, true);
-
-  updater_bridge_consumer()->OnSuccessfulSettingChange(
-      PasswordManagerSetting::kAutoSignIn);
-  updater_bridge_consumer()->OnFailedSettingChange(
-      PasswordManagerSetting::kOfferToSavePasswords,
-      AndroidBackendAPIErrorCode::kUnexpectedError);
-
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kOfferToSavePasswords));
-  EXPECT_FALSE(settings_service()->IsSettingEnabled(
-      PasswordManagerSetting::kAutoSignIn));
-
-  EXPECT_FALSE(pref_service()->GetBoolean(
-      password_manager::prefs::kSettingsMigratedToUPMLocal));
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationFailed.OfferToSavePasswords."
-      "APIError2",
-      AndroidBackendAPIErrorCode::kUnexpectedError, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "PasswordManager.PasswordSettingsMigrationSucceeded2", false, 1);
-}
-
-TEST_F(PasswordManagerSettingsServiceAndroidMigrationImplTestLocalUsers,
-       FetchesBiometricAuthenticationBeforeFillingSetting) {
-  base::test::ScopedFeatureList scoped_feature_list{
-      password_manager::features::kBiometricTouchToFill};
-  InitializeSettingsService(/*password_sync_enabled=*/false,
-                            /*setting_sync_enabled=*/false);
-
-  ExpectSettingsRetrievalFromBackend(std::nullopt, /*times=*/1);
-  lifecycle_helper()->OnForegroundSessionStart();
-}
diff --git a/chrome/browser/password_manager/android/password_manager_util_bridge.cc b/chrome/browser/password_manager/android/password_manager_util_bridge.cc
index f04cbf0..a641f39 100644
--- a/chrome/browser/password_manager/android/password_manager_util_bridge.cc
+++ b/chrome/browser/password_manager/android/password_manager_util_bridge.cc
@@ -52,14 +52,6 @@
   return password_manager_android_util::AreMinUpmRequirementsMet();
 }
 
-jint JNI_PasswordManagerUtilBridge_GetPasswordAccessLossWarningType(
-    JNIEnv* env,
-    PrefService* pref_service) {
-  return static_cast<int>(
-      password_manager_android_util::GetPasswordAccessLossWarningType(
-          pref_service));
-}
-
 base::android::ScopedJavaLocalRef<jstring>
 JNI_PasswordManagerUtilBridge_GetAutoExportCsvFilePath(JNIEnv* env,
                                                        Profile* profile) {
diff --git a/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc
index ab40aa5..444f5a4 100644
--- a/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc
+++ b/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc
@@ -171,8 +171,6 @@
         prefs::kUnenrolledFromGoogleMobileServicesDueToErrors, false);
     prefs_.registry()->RegisterIntegerPref(
         prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
-    prefs_.registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
-                                          20.22);
     prefs_.registry()->RegisterIntegerPref(
         prefs::kPasswordsUseUPMLocalAndSeparateStores,
         static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOff));
@@ -681,7 +679,6 @@
   EXPECT_NE(prefs()->GetInteger(
                 prefs::kCurrentMigrationVersionToGoogleMobileServices),
             0);
-  EXPECT_NE(prefs()->GetDouble(prefs::kTimeOfLastMigrationAttempt), 0.0);
 
   histogram_tester.ExpectBucketCount(kBackendErrorCodeMetric, 7, 1);
   histogram_tester.ExpectBucketCount(kBackendApiErrorMetric,
@@ -730,7 +727,6 @@
   EXPECT_NE(prefs()->GetInteger(
                 prefs::kCurrentMigrationVersionToGoogleMobileServices),
             0);
-  EXPECT_NE(prefs()->GetDouble(prefs::kTimeOfLastMigrationAttempt), 0.0);
 
   histogram_tester.ExpectBucketCount(kBackendErrorCodeMetric, 7, 1);
   histogram_tester.ExpectBucketCount(
@@ -1110,7 +1106,6 @@
   EXPECT_NE(prefs()->GetInteger(
                 prefs::kCurrentMigrationVersionToGoogleMobileServices),
             0);
-  EXPECT_NE(prefs()->GetDouble(prefs::kTimeOfLastMigrationAttempt), 0.0);
   EXPECT_FALSE(backend().IsAbleToSavePasswords());
   histogram_tester.ExpectBucketCount(kBackendErrorCodeMetric, 7, 1);
   histogram_tester.ExpectBucketCount(kBackendApiErrorMetric,
diff --git a/chrome/browser/password_manager/android/password_store_backend_migration_decorator.cc b/chrome/browser/password_manager/android/password_store_backend_migration_decorator.cc
deleted file mode 100644
index 6460bcf..0000000
--- a/chrome/browser/password_manager/android/password_store_backend_migration_decorator.cc
+++ /dev/null
@@ -1,214 +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/password_manager/android/password_store_backend_migration_decorator.h"
-
-#include "base/barrier_callback.h"
-#include "base/barrier_closure.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/memory/weak_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chrome/browser/password_manager/android/built_in_backend_to_android_backend_migrator.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync/model/proxy_data_type_controller_delegate.h"
-#include "components/sync/service/sync_service.h"
-
-namespace password_manager {
-
-PasswordStoreBackendMigrationDecorator::PasswordStoreBackendMigrationDecorator(
-    std::unique_ptr<PasswordStoreBackend> built_in_backend,
-    std::unique_ptr<PasswordStoreBackend> android_backend,
-    PrefService* prefs)
-    : built_in_backend_(std::move(built_in_backend)),
-      android_backend_(std::move(android_backend)),
-      prefs_(prefs) {
-  CHECK(built_in_backend_);
-  CHECK(android_backend_);
-  migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
-      built_in_backend_.get(), android_backend_.get(), prefs_);
-}
-
-PasswordStoreBackendMigrationDecorator::
-    ~PasswordStoreBackendMigrationDecorator() = default;
-
-void PasswordStoreBackendMigrationDecorator::InitBackend(
-    AffiliatedMatchHelper* affiliated_match_helper,
-    RemoteChangesReceived remote_form_changes_received,
-    base::RepeatingClosure sync_enabled_or_disabled_cb,
-    base::OnceCallback<void(bool)> completion) {
-  base::RepeatingCallback<void(bool)> pending_initialization_calls =
-      base::BarrierCallback<bool>(
-          /*num_callbacks=*/2,
-          base::BindOnce([](const std::vector<bool>& results) {
-            return std::ranges::all_of(results, std::identity());
-          }).Then(std::move(completion)));
-  auto remote_changes_callback = base::BindRepeating(
-      &PasswordStoreBackendMigrationDecorator::OnRemoteFormChangesReceived,
-      weak_ptr_factory_.GetWeakPtr(), remote_form_changes_received);
-
-  built_in_backend_->InitBackend(
-      affiliated_match_helper,
-      base::BindRepeating(remote_changes_callback,
-                          built_in_backend_->AsWeakPtr()),
-      std::move(sync_enabled_or_disabled_cb), pending_initialization_calls);
-  android_backend_->InitBackend(
-      /*affiliated_match_helper=*/nullptr,
-      base::BindRepeating(remote_changes_callback,
-                          android_backend_->AsWeakPtr()),
-      base::NullCallback(), pending_initialization_calls);
-
-  metrics_util::LogLocalPwdMigrationProgressState(
-      metrics_util::LocalPwdMigrationProgressState::kScheduled);
-  // Post delayed task to start migration of local passwords to avoid extra load
-  // on start-up.
-  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::
-                         StartMigrationOfLocalPasswords,
-                     migrator_->GetWeakPtr()),
-      kLocalPasswordsMigrationToAndroidBackendDelay);
-}
-
-void PasswordStoreBackendMigrationDecorator::Shutdown(
-    base::OnceClosure shutdown_completed) {
-  weak_ptr_factory_.InvalidateWeakPtrs();
-  migrator_.reset();
-
-  auto shutdown_closure =
-      base::BarrierClosure(2, std::move(shutdown_completed));
-  built_in_backend_->Shutdown(
-      base::BindOnce(shutdown_closure)
-          .Then(base::OnceClosure(
-              base::DoNothingWithBoundArgs(std::move(built_in_backend_)))));
-  android_backend_->Shutdown(
-      base::BindOnce(shutdown_closure)
-          .Then(base::OnceClosure(
-              base::DoNothingWithBoundArgs(std::move(android_backend_)))));
-}
-
-bool PasswordStoreBackendMigrationDecorator::IsAbleToSavePasswords() {
-  // Suppress saving while the migration of local passwords is ongoing, to avoid
-  // the migration "forgetting" any new passwords.
-  return active_backend()->IsAbleToSavePasswords() &&
-         !(migrator_ && migrator_->migration_in_progress());
-}
-
-void PasswordStoreBackendMigrationDecorator::GetAllLoginsAsync(
-    LoginsOrErrorReply callback) {
-  active_backend()->GetAllLoginsAsync(std::move(callback));
-}
-
-void PasswordStoreBackendMigrationDecorator::
-    GetAllLoginsWithAffiliationAndBrandingAsync(LoginsOrErrorReply callback) {
-  active_backend()->GetAllLoginsWithAffiliationAndBrandingAsync(
-      std::move(callback));
-}
-
-void PasswordStoreBackendMigrationDecorator::GetAutofillableLoginsAsync(
-    LoginsOrErrorReply callback) {
-  active_backend()->GetAutofillableLoginsAsync(std::move(callback));
-}
-
-void PasswordStoreBackendMigrationDecorator::FillMatchingLoginsAsync(
-    LoginsOrErrorReply callback,
-    bool include_psl,
-    const std::vector<PasswordFormDigest>& forms) {
-  active_backend()->FillMatchingLoginsAsync(std::move(callback), include_psl,
-                                            forms);
-}
-
-void PasswordStoreBackendMigrationDecorator::GetGroupedMatchingLoginsAsync(
-    const PasswordFormDigest& form_digest,
-    LoginsOrErrorReply callback) {
-  active_backend()->GetGroupedMatchingLoginsAsync(std::move(form_digest),
-                                                  std::move(callback));
-}
-
-void PasswordStoreBackendMigrationDecorator::AddLoginAsync(
-    const PasswordForm& form,
-    PasswordChangesOrErrorReply callback) {
-  active_backend()->AddLoginAsync(form, std::move(callback));
-}
-
-void PasswordStoreBackendMigrationDecorator::UpdateLoginAsync(
-    const PasswordForm& form,
-    PasswordChangesOrErrorReply callback) {
-  active_backend()->UpdateLoginAsync(form, std::move(callback));
-}
-
-void PasswordStoreBackendMigrationDecorator::RemoveLoginAsync(
-    const base::Location& location,
-    const PasswordForm& form,
-    PasswordChangesOrErrorReply callback) {
-  active_backend()->RemoveLoginAsync(location, form, std::move(callback));
-  if (UsesSplitStoresAndUPMForLocal(prefs_)) {
-    built_in_backend_->RemoveLoginAsync(location, form, base::DoNothing());
-  }
-}
-
-void PasswordStoreBackendMigrationDecorator::RemoveLoginsCreatedBetweenAsync(
-    const base::Location& location,
-    base::Time delete_begin,
-    base::Time delete_end,
-    base::OnceCallback<void(bool)> sync_completion,
-    PasswordChangesOrErrorReply callback) {
-  active_backend()->RemoveLoginsCreatedBetweenAsync(
-      location, delete_begin, delete_end, std::move(sync_completion),
-      std::move(callback));
-  if (UsesSplitStoresAndUPMForLocal(prefs_)) {
-    built_in_backend_->RemoveLoginsCreatedBetweenAsync(
-        location, delete_begin, delete_end, base::NullCallback(),
-        base::DoNothing());
-  }
-}
-
-void PasswordStoreBackendMigrationDecorator::DisableAutoSignInForOriginsAsync(
-    const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
-    base::OnceClosure completion) {
-  active_backend()->DisableAutoSignInForOriginsAsync(origin_filter,
-                                                     std::move(completion));
-}
-
-SmartBubbleStatsStore*
-PasswordStoreBackendMigrationDecorator::GetSmartBubbleStatsStore() {
-  return nullptr;
-}
-
-std::unique_ptr<syncer::DataTypeControllerDelegate>
-PasswordStoreBackendMigrationDecorator::CreateSyncControllerDelegate() {
-  return built_in_backend_->CreateSyncControllerDelegate();
-}
-
-void PasswordStoreBackendMigrationDecorator::OnSyncServiceInitialized(
-    syncer::SyncService* sync_service) {
-  // TODO: b/323880741 - make sure `migrator_` doesn't require `sync_service`
-  // for local password migration.
-  if (migrator_) {
-    migrator_->OnSyncServiceInitialized(sync_service);
-  }
-}
-
-base::WeakPtr<PasswordStoreBackend>
-PasswordStoreBackendMigrationDecorator::AsWeakPtr() {
-  return weak_ptr_factory_.GetWeakPtr();
-}
-
-void PasswordStoreBackendMigrationDecorator::OnRemoteFormChangesReceived(
-    RemoteChangesReceived remote_form_changes_received,
-    base::WeakPtr<PasswordStoreBackend> from_backend,
-    std::optional<PasswordStoreChangeList> changes) {
-  if (from_backend && from_backend.get() == active_backend()) {
-    remote_form_changes_received.Run(std::move(changes));
-  }
-}
-
-PasswordStoreBackend* PasswordStoreBackendMigrationDecorator::active_backend() {
-  return UsesSplitStoresAndUPMForLocal(prefs_) ? android_backend_.get()
-                                               : built_in_backend_.get();
-}
-
-}  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_backend_migration_decorator.h b/chrome/browser/password_manager/android/password_store_backend_migration_decorator.h
deleted file mode 100644
index 6e19e10..0000000
--- a/chrome/browser/password_manager/android/password_store_backend_migration_decorator.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BACKEND_MIGRATION_DECORATOR_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BACKEND_MIGRATION_DECORATOR_H_
-
-#include <memory>
-
-#include "base/functional/callback_forward.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/sync/service/sync_service_observer.h"
-
-class PrefService;
-
-namespace password_manager {
-
-class BuiltInBackendToAndroidBackendMigrator;
-
-// Exposed here for testing.
-inline constexpr base::TimeDelta kLocalPasswordsMigrationToAndroidBackendDelay =
-    base::Seconds(5);
-
-// This backend migrates local passwords from `built_in_backend` to
-// `android_backend`. Migration is scheduled after InitBackend() call. While
-// migration is ongoing password saving is suppressed. Before migration is
-// finished `built_in_backend` is used for all operations. After migration is
-// complete `android_backend` is used instead, although password deletions are
-// still propagated to `built_in_backend` as well.
-class PasswordStoreBackendMigrationDecorator : public PasswordStoreBackend {
- public:
-  PasswordStoreBackendMigrationDecorator(
-      std::unique_ptr<PasswordStoreBackend> built_in_backend,
-      std::unique_ptr<PasswordStoreBackend> android_backend,
-      PrefService* prefs);
-  PasswordStoreBackendMigrationDecorator(
-      const PasswordStoreBackendMigrationDecorator&) = delete;
-  PasswordStoreBackendMigrationDecorator(
-      PasswordStoreBackendMigrationDecorator&&) = delete;
-  PasswordStoreBackendMigrationDecorator& operator=(
-      const PasswordStoreBackendMigrationDecorator&) = delete;
-  PasswordStoreBackendMigrationDecorator& operator=(
-      PasswordStoreBackendMigrationDecorator&&) = delete;
-  ~PasswordStoreBackendMigrationDecorator() override;
-
- private:
-  // Implements PasswordStoreBackend interface.
-  void InitBackend(AffiliatedMatchHelper* affiliated_match_helper,
-                   RemoteChangesReceived remote_form_changes_received,
-                   base::RepeatingClosure sync_enabled_or_disabled_cb,
-                   base::OnceCallback<void(bool)> completion) override;
-  void Shutdown(base::OnceClosure shutdown_completed) override;
-  bool IsAbleToSavePasswords() override;
-  void GetAllLoginsAsync(LoginsOrErrorReply callback) override;
-  void GetAllLoginsWithAffiliationAndBrandingAsync(
-      LoginsOrErrorReply callback) override;
-  void GetAutofillableLoginsAsync(LoginsOrErrorReply callback) override;
-  void FillMatchingLoginsAsync(
-      LoginsOrErrorReply callback,
-      bool include_psl,
-      const std::vector<PasswordFormDigest>& forms) override;
-  void GetGroupedMatchingLoginsAsync(const PasswordFormDigest& form_digest,
-                                     LoginsOrErrorReply callback) override;
-  void AddLoginAsync(const PasswordForm& form,
-                     PasswordChangesOrErrorReply callback) override;
-  void UpdateLoginAsync(const PasswordForm& form,
-                        PasswordChangesOrErrorReply callback) override;
-  void RemoveLoginAsync(const base::Location& location,
-                        const PasswordForm& form,
-                        PasswordChangesOrErrorReply callback) override;
-  void RemoveLoginsCreatedBetweenAsync(
-      const base::Location& location,
-      base::Time delete_begin,
-      base::Time delete_end,
-      base::OnceCallback<void(bool)> sync_completion,
-      PasswordChangesOrErrorReply callback) override;
-  void DisableAutoSignInForOriginsAsync(
-      const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
-      base::OnceClosure completion) override;
-  SmartBubbleStatsStore* GetSmartBubbleStatsStore() override;
-  std::unique_ptr<syncer::DataTypeControllerDelegate>
-  CreateSyncControllerDelegate() override;
-  void OnSyncServiceInitialized(syncer::SyncService* sync_service) override;
-  base::WeakPtr<PasswordStoreBackend> AsWeakPtr() override;
-
-  // Forwards the (possible) forms changes caused by a remote event to the
-  // backend. Only changes from the active_backend() are taken into
-  // consideration. For `android_backend_` they can happen on foreground event.
-  void OnRemoteFormChangesReceived(
-      RemoteChangesReceived remote_form_changes_received,
-      base::WeakPtr<PasswordStoreBackend> from_backend,
-      std::optional<PasswordStoreChangeList> changes);
-
-  PasswordStoreBackend* active_backend();
-
-  std::unique_ptr<PasswordStoreBackend> built_in_backend_;
-  std::unique_ptr<PasswordStoreBackend> android_backend_;
-
-  const raw_ptr<PrefService> prefs_ = nullptr;
-
-  // Helper class responsible for actually migrating passwords from one backend
-  // to another.
-  std::unique_ptr<BuiltInBackendToAndroidBackendMigrator> migrator_;
-
-  base::WeakPtrFactory<PasswordStoreBackendMigrationDecorator>
-      weak_ptr_factory_{this};
-};
-
-}  // namespace password_manager
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_BACKEND_MIGRATION_DECORATOR_H_
diff --git a/chrome/browser/password_manager/android/password_store_backend_migration_decorator_unittest.cc b/chrome/browser/password_manager/android/password_store_backend_migration_decorator_unittest.cc
deleted file mode 100644
index fa17608..0000000
--- a/chrome/browser/password_manager/android/password_store_backend_migration_decorator_unittest.cc
+++ /dev/null
@@ -1,527 +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/password_manager/android/password_store_backend_migration_decorator.h"
-
-#include "base/functional/callback.h"
-#include "base/functional/callback_helpers.h"
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/time/time.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "components/password_manager/core/browser/password_store/mock_password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/signin/public/base/signin_pref_names.h"
-#include "components/sync/test/test_sync_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace password_manager {
-namespace {
-
-using ::testing::_;
-using ::testing::ElementsAreArray;
-using ::testing::Mock;
-using ::testing::NiceMock;
-using ::testing::Ref;
-using ::testing::Return;
-using ::testing::VariantWith;
-using ::testing::WithArg;
-using ::testing::WithArgs;
-
-PasswordForm CreateTestForm() {
-  PasswordForm form;
-  form.username_value = u"admin";
-  form.password_value = u"admin";
-  form.signon_realm = "https://admin.google.com/";
-  form.url = GURL(form.signon_realm);
-  return form;
-}
-
-}  // namespace
-
-class PasswordStoreBackendMigrationDecoratorTest : public testing::Test {
- protected:
-  void SetUp() override {
-    prefs_.registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
-                                          0);
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kUnenrolledFromGoogleMobileServicesDueToErrors, false);
-    prefs_.registry()->RegisterIntegerPref(
-        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-    prefs_.registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-                kOffAndMigrationPending));
-
-    auto built_in_backend =
-        std::make_unique<NiceMock<MockPasswordStoreBackend>>();
-    auto android_backend =
-        std::make_unique<NiceMock<MockPasswordStoreBackend>>();
-    built_in_backend_ = built_in_backend.get();
-    android_backend_ = android_backend.get();
-    backend_migration_decorator_ =
-        std::make_unique<PasswordStoreBackendMigrationDecorator>(
-            std::move(built_in_backend), std::move(android_backend), &prefs_);
-    sync_service_.GetUserSettings()->SetSelectedTypes(
-        /*sync_everything=*/false, /*types=*/{});
-    backend_migration_decorator()->OnSyncServiceInitialized(&sync_service_);
-  }
-
-  void TearDown() override {
-    EXPECT_CALL(android_backend(), Shutdown);
-    EXPECT_CALL(built_in_backend(), Shutdown);
-    built_in_backend_ = nullptr;
-    android_backend_ = nullptr;
-    backend_migration_decorator()->Shutdown(base::DoNothing());
-  }
-
-  PasswordStoreBackend* backend_migration_decorator() {
-    return backend_migration_decorator_.get();
-  }
-  MockPasswordStoreBackend& built_in_backend() { return *built_in_backend_; }
-  MockPasswordStoreBackend& android_backend() { return *android_backend_; }
-
-  TestingPrefServiceSimple& prefs() { return prefs_; }
-
-  void RunUntilIdle() { task_env_.RunUntilIdle(); }
-
-  void FastForwardUntilNoTasksRemain() {
-    task_env_.FastForwardUntilNoTasksRemain();
-  }
-
-  void FastForwardBy(base::TimeDelta delta) { task_env_.FastForwardBy(delta); }
-
-  int GetPendingMainThreadTaskCount() {
-    return task_env_.GetPendingMainThreadTaskCount();
-  }
-
- private:
-  base::test::SingleThreadTaskEnvironment task_env_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  raw_ptr<NiceMock<MockPasswordStoreBackend>> built_in_backend_;
-  raw_ptr<NiceMock<MockPasswordStoreBackend>> android_backend_;
-  TestingPrefServiceSimple prefs_;
-  syncer::TestSyncService sync_service_;
-  std::unique_ptr<PasswordStoreBackendMigrationDecorator>
-      backend_migration_decorator_;
-};
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       RecordsSchedulingOfLocalPwdMigration) {
-  base::HistogramTester histogram_tester;
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          prefs::UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending));
-  backend_migration_decorator()->InitBackend(
-      /*affiliated_match_helper=*/nullptr,
-      /*remote_form_changes_received=*/base::DoNothing(),
-      /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
-      /*completion=*/base::DoNothing());
-  // Migration should be scheduled.
-  ASSERT_EQ(1, GetPendingMainThreadTaskCount());
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "ProgressState",
-      metrics_util::LocalPwdMigrationProgressState::kScheduled, 1);
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, GetAllLoginsAsync) {
-  EXPECT_CALL(built_in_backend(), GetAllLoginsAsync);
-  EXPECT_CALL(android_backend(), GetAllLoginsAsync).Times(0);
-
-  backend_migration_decorator()->GetAllLoginsAsync(base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       GetAllLoginsAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), GetAllLoginsAsync).Times(0);
-  EXPECT_CALL(android_backend(), GetAllLoginsAsync);
-
-  backend_migration_decorator()->GetAllLoginsAsync(base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, IsAbleToSavePasswords) {
-  EXPECT_CALL(built_in_backend(), IsAbleToSavePasswords).WillOnce(Return(true));
-  EXPECT_CALL(android_backend(), IsAbleToSavePasswords).Times(0);
-
-  EXPECT_TRUE(backend_migration_decorator()->IsAbleToSavePasswords());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       IsAbleToSavePasswordsAfterMigration) {
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), IsAbleToSavePasswords).Times(0);
-  EXPECT_CALL(android_backend(), IsAbleToSavePasswords).WillOnce(Return(false));
-
-  EXPECT_FALSE(backend_migration_decorator()->IsAbleToSavePasswords());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       GetAllLoginsWithAffiliationAndBrandingAsync) {
-  EXPECT_CALL(built_in_backend(), GetAllLoginsWithAffiliationAndBrandingAsync);
-  EXPECT_CALL(android_backend(), GetAllLoginsWithAffiliationAndBrandingAsync)
-      .Times(0);
-
-  backend_migration_decorator()->GetAllLoginsWithAffiliationAndBrandingAsync(
-      base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       GetAllLoginsWithAffiliationAndBrandingAsyncAfterMigration) {
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), GetAllLoginsWithAffiliationAndBrandingAsync)
-      .Times(0);
-  EXPECT_CALL(android_backend(), GetAllLoginsWithAffiliationAndBrandingAsync);
-
-  backend_migration_decorator()->GetAllLoginsWithAffiliationAndBrandingAsync(
-      base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, GetAutofillableLoginsAsync) {
-  EXPECT_CALL(built_in_backend(), GetAutofillableLoginsAsync);
-  EXPECT_CALL(android_backend(), GetAutofillableLoginsAsync).Times(0);
-
-  backend_migration_decorator()->GetAutofillableLoginsAsync(base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       GetAutofillableLoginsAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), GetAutofillableLoginsAsync).Times(0);
-  EXPECT_CALL(android_backend(), GetAutofillableLoginsAsync);
-
-  backend_migration_decorator()->GetAutofillableLoginsAsync(base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, FillMatchingLoginsAsync) {
-  std::vector<PasswordFormDigest> forms = {
-      PasswordFormDigest(PasswordForm::Scheme::kHtml, "https://google.com/",
-                         GURL("https://google.com/"))};
-
-  EXPECT_CALL(built_in_backend(),
-              FillMatchingLoginsAsync(_, false, ElementsAreArray(forms)));
-  EXPECT_CALL(android_backend(), FillMatchingLoginsAsync).Times(0);
-
-  backend_migration_decorator()->FillMatchingLoginsAsync(
-      base::DoNothing(), /*include_psl=*/false, forms);
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       FillMatchingLoginsAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  std::vector<PasswordFormDigest> forms = {
-      PasswordFormDigest(PasswordForm::Scheme::kHtml, "https://google.com/",
-                         GURL("https://google.com/"))};
-  EXPECT_CALL(built_in_backend(), FillMatchingLoginsAsync).Times(0);
-  EXPECT_CALL(android_backend(),
-              FillMatchingLoginsAsync(_, false, ElementsAreArray(forms)));
-
-  backend_migration_decorator()->FillMatchingLoginsAsync(
-      base::DoNothing(), /*include_psl=*/false, forms);
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       GetGroupedMatchingLoginsAsync) {
-  PasswordFormDigest form_digest(PasswordForm::Scheme::kHtml,
-                                 "https://google.com/",
-                                 GURL("https://google.com/"));
-  EXPECT_CALL(built_in_backend(),
-              GetGroupedMatchingLoginsAsync(Ref(form_digest), _));
-  EXPECT_CALL(android_backend(), GetGroupedMatchingLoginsAsync).Times(0);
-
-  backend_migration_decorator()->GetGroupedMatchingLoginsAsync(
-      form_digest, base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       GetGroupedMatchingLoginsAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  PasswordFormDigest form_digest(PasswordForm::Scheme::kHtml,
-                                 "https://google.com/",
-                                 GURL("https://google.com/"));
-  EXPECT_CALL(built_in_backend(), GetGroupedMatchingLoginsAsync).Times(0);
-  EXPECT_CALL(android_backend(),
-              GetGroupedMatchingLoginsAsync(Ref(form_digest), _));
-
-  backend_migration_decorator()->GetGroupedMatchingLoginsAsync(
-      form_digest, base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, AddLoginAsync) {
-  EXPECT_CALL(built_in_backend(), AddLoginAsync(CreateTestForm(), _));
-  EXPECT_CALL(android_backend(), AddLoginAsync).Times(0);
-
-  backend_migration_decorator()->AddLoginAsync(CreateTestForm(),
-                                               base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       AddLoginAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), AddLoginAsync).Times(0);
-  EXPECT_CALL(android_backend(), AddLoginAsync(CreateTestForm(), _));
-
-  backend_migration_decorator()->AddLoginAsync(CreateTestForm(),
-                                               base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, UpdateLoginAsync) {
-  EXPECT_CALL(built_in_backend(), UpdateLoginAsync(CreateTestForm(), _));
-  EXPECT_CALL(android_backend(), UpdateLoginAsync).Times(0);
-
-  backend_migration_decorator()->UpdateLoginAsync(CreateTestForm(),
-                                                  base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       UpdateLoginAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), UpdateLoginAsync).Times(0);
-  EXPECT_CALL(android_backend(), UpdateLoginAsync(CreateTestForm(), _));
-
-  backend_migration_decorator()->UpdateLoginAsync(CreateTestForm(),
-                                                  base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, RemoveLoginAsync) {
-  EXPECT_CALL(built_in_backend(), RemoveLoginAsync(_, CreateTestForm(), _));
-  EXPECT_CALL(android_backend(), RemoveLoginAsync).Times(0);
-
-  backend_migration_decorator()->RemoveLoginAsync(FROM_HERE, CreateTestForm(),
-                                                  base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       RemoveLoginAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  EXPECT_CALL(built_in_backend(), RemoveLoginAsync(_, CreateTestForm(), _));
-  EXPECT_CALL(android_backend(), RemoveLoginAsync(_, CreateTestForm(), _));
-
-  backend_migration_decorator()->RemoveLoginAsync(FROM_HERE, CreateTestForm(),
-                                                  base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       RemoveLoginsCreatedBetweenAsync) {
-  base::Time delete_begin = base::Time::FromTimeT(1000);
-  base::Time delete_end = base::Time::FromTimeT(2000);
-
-  EXPECT_CALL(built_in_backend(), RemoveLoginsCreatedBetweenAsync(
-                                      _, delete_begin, delete_end, _, _));
-  EXPECT_CALL(android_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);
-
-  backend_migration_decorator()->RemoveLoginsCreatedBetweenAsync(
-      FROM_HERE, delete_begin, delete_end, base::OnceCallback<void(bool)>(),
-      base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       RemoveLoginsCreatedBetweenAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  base::Time delete_begin = base::Time::FromTimeT(1000);
-  base::Time delete_end = base::Time::FromTimeT(2000);
-  EXPECT_CALL(built_in_backend(), RemoveLoginsCreatedBetweenAsync(
-                                      _, delete_begin, delete_end, _, _));
-  EXPECT_CALL(android_backend(), RemoveLoginsCreatedBetweenAsync(
-                                     _, delete_begin, delete_end, _, _));
-
-  backend_migration_decorator()->RemoveLoginsCreatedBetweenAsync(
-      FROM_HERE, delete_begin, delete_end, base::OnceCallback<void(bool)>(),
-      base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       DisableAutoSignInForOriginsAsync) {
-  base::RepeatingCallback<bool(const GURL&)> url_filter =
-      base::BindRepeating([](const GURL& url) { return true; });
-
-  EXPECT_CALL(built_in_backend(),
-              DisableAutoSignInForOriginsAsync(url_filter, _));
-  EXPECT_CALL(android_backend(), DisableAutoSignInForOriginsAsync).Times(0);
-
-  backend_migration_decorator()->DisableAutoSignInForOriginsAsync(
-      url_filter, base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       DisableAutoSignInForOriginsAsyncAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-
-  base::RepeatingCallback<bool(const GURL&)> url_filter =
-      base::BindRepeating([](const GURL& url) { return true; });
-  EXPECT_CALL(built_in_backend(), DisableAutoSignInForOriginsAsync).Times(0);
-  EXPECT_CALL(android_backend(),
-              DisableAutoSignInForOriginsAsync(url_filter, _));
-
-  backend_migration_decorator()->DisableAutoSignInForOriginsAsync(
-      url_filter, base::DoNothing());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       DisableSavingDuringLocalPasswordsMigration) {
-  backend_migration_decorator()->InitBackend(
-      /*affiliated_match_helper=*/nullptr,
-      /*remote_form_changes_received=*/base::DoNothing(),
-      /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
-      /*completion=*/base::DoNothing());
-
-  // True so far because the migration is deferred.
-  EXPECT_CALL(built_in_backend(), IsAbleToSavePasswords)
-      .WillRepeatedly(Return(true));
-  ASSERT_TRUE(backend_migration_decorator()->IsAbleToSavePasswords());
-
-  FastForwardUntilNoTasksRemain();
-
-  // False now because the migration is ongoing.
-  EXPECT_FALSE(backend_migration_decorator()->IsAbleToSavePasswords());
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest, RemoteFormChangesReceived) {
-  base::MockCallback<PasswordStoreBackend::RemoteChangesReceived>
-      original_callback;
-
-  // Both backends receive a callback that they trigger for new remote changes.
-  PasswordStoreBackend::RemoteChangesReceived built_in_remote_changes_callback;
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(testing::SaveArg<1>(&built_in_remote_changes_callback));
-  PasswordStoreBackend::RemoteChangesReceived android_remote_changes_callback;
-  EXPECT_CALL(android_backend(), InitBackend)
-      .WillOnce(testing::SaveArg<1>(&android_remote_changes_callback));
-  backend_migration_decorator()->InitBackend(
-      nullptr, original_callback.Get(), base::DoNothing(), base::DoNothing());
-
-  EXPECT_CALL(original_callback, Run).Times(0);
-  android_remote_changes_callback.Run(std::nullopt);
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-
-  EXPECT_CALL(original_callback, Run);
-  built_in_remote_changes_callback.Run(std::nullopt);
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       RemoteFormChangesReceivedAfterMigration) {
-  // Indicate completeness of local password migration.
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-  base::MockCallback<PasswordStoreBackend::RemoteChangesReceived>
-      original_callback;
-
-  PasswordStoreBackend::RemoteChangesReceived built_in_remote_changes_callback;
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(testing::SaveArg<1>(&built_in_remote_changes_callback));
-  PasswordStoreBackend::RemoteChangesReceived android_remote_changes_callback;
-  EXPECT_CALL(android_backend(), InitBackend)
-      .WillOnce(testing::SaveArg<1>(&android_remote_changes_callback));
-  backend_migration_decorator()->InitBackend(
-      nullptr, original_callback.Get(), base::DoNothing(), base::DoNothing());
-
-  EXPECT_CALL(original_callback, Run);
-  android_remote_changes_callback.Run(std::nullopt);
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-
-  EXPECT_CALL(original_callback, Run).Times(0);
-  built_in_remote_changes_callback.Run(std::nullopt);
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       CallCompletionCallbackAfterInit) {
-  base::MockCallback<base::OnceCallback<void(bool)>> completion_callback;
-
-  // Both backends need to be invoked for a successful completion call.
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(WithArg<3>(
-          testing::Invoke([](base::OnceCallback<void(bool)> reply) -> void {
-            std::move(reply).Run(true);
-          })));
-
-  base::OnceCallback<void(bool)> captured_android_backend_reply;
-  EXPECT_CALL(android_backend(), InitBackend)
-      .WillOnce(WithArg<3>(
-          testing::Invoke([&](base::OnceCallback<void(bool)> reply) -> void {
-            captured_android_backend_reply = std::move(reply);
-          })));
-
-  backend_migration_decorator()->InitBackend(
-      nullptr, base::DoNothing(), base::DoNothing(), completion_callback.Get());
-
-  EXPECT_CALL(completion_callback, Run(true));
-  std::move(captured_android_backend_reply).Run(true);
-}
-
-TEST_F(PasswordStoreBackendMigrationDecoratorTest,
-       MigrationIsStartedWithDelayAfterInit) {
-  prefs().SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          prefs::UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending));
-
-  backend_migration_decorator()->InitBackend(
-      nullptr, /* remote_form_changes_received= */ base::DoNothing(),
-      /* sync_enabled_or_disabled_cb= */ base::DoNothing(),
-      /* completion= */ base::DoNothing());
-  // Migration should be scheduled.
-  EXPECT_EQ(1, GetPendingMainThreadTaskCount());
-
-  FastForwardBy(kLocalPasswordsMigrationToAndroidBackendDelay);
-  // Migration should be started by now.
-  EXPECT_EQ(0, GetPendingMainThreadTaskCount());
-}
-
-}  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_proxy_backend.cc b/chrome/browser/password_manager/android/password_store_proxy_backend.cc
deleted file mode 100644
index 95ec428..0000000
--- a/chrome/browser/password_manager/android/password_store_proxy_backend.cc
+++ /dev/null
@@ -1,318 +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 "chrome/browser/password_manager/android/password_store_proxy_backend.h"
-
-#include <algorithm>
-#include <functional>
-#include <memory>
-#include <utility>
-#include <variant>
-#include <vector>
-
-#include "base/barrier_callback.h"
-#include "base/barrier_closure.h"
-#include "base/functional/callback.h"
-#include "base/functional/callback_forward.h"
-#include "base/functional/callback_helpers.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/not_fatal_until.h"
-#include "base/notreached.h"
-#include "base/strings/strcat.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend_error.h"
-#include "components/password_manager/core/browser/password_sync_util.h"
-#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
-#include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync/model/proxy_data_type_controller_delegate.h"
-#include "components/sync/service/sync_service.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-
-namespace password_manager {
-
-namespace {
-
-void InvokeCallbackWithCombinedStatus(base::OnceCallback<void(bool)> completion,
-                                      std::vector<bool> statuses) {
-  std::move(completion).Run(std::ranges::all_of(statuses, std::identity()));
-}
-
-void RecordPasswordDeletionResult(PasswordChangesOrError result) {
-  bool is_operation_successful = true;
-  if (std::holds_alternative<PasswordStoreBackendError>(result)) {
-    is_operation_successful = false;
-  }
-  base::UmaHistogramBoolean(
-      "PasswordManager.PasswordStoreProxyBackend.PasswordRemovalStatus",
-      is_operation_successful);
-  if (!is_operation_successful) {
-    return;
-  }
-
-  PasswordChanges changes = std::get<PasswordChanges>(std::move(result));
-
-  if (changes.has_value()) {
-    base::UmaHistogramCounts1000(
-        "PasswordManager.PasswordStoreProxyBackend.RemovedPasswordCount",
-        changes.value().size());
-  }
-}
-
-}  // namespace
-
-PasswordStoreProxyBackend::PasswordStoreProxyBackend(
-    std::unique_ptr<PasswordStoreBackend> built_in_backend,
-    std::unique_ptr<PasswordStoreBackend> android_backend,
-    PrefService* prefs)
-    : built_in_backend_(std::move(built_in_backend)),
-      android_backend_(std::move(android_backend)),
-      prefs_(prefs) {
-  CHECK(!password_manager::UsesSplitStoresAndUPMForLocal(prefs_));
-}
-
-PasswordStoreProxyBackend::~PasswordStoreProxyBackend() = default;
-
-void PasswordStoreProxyBackend::InitBackend(
-    AffiliatedMatchHelper* affiliated_match_helper,
-    RemoteChangesReceived remote_form_changes_received,
-    base::RepeatingClosure sync_enabled_or_disabled_cb,
-    base::OnceCallback<void(bool)> completion) {
-  base::RepeatingCallback<void(bool)> pending_initialization_calls =
-      base::BarrierCallback<bool>(
-          /*num_callbacks=*/2, base::BindOnce(&InvokeCallbackWithCombinedStatus,
-                                              std::move(completion)));
-
-  // Both backends need to be initialized, so using the helpers for main/shadow
-  // backend is unnecessary and won't work since the sync status may not be
-  // available yet.
-  built_in_backend_->InitBackend(
-      affiliated_match_helper,
-      base::BindRepeating(
-          &PasswordStoreProxyBackend::OnRemoteFormChangesReceived,
-          weak_ptr_factory_.GetWeakPtr(),
-          CallbackOriginatesFromAndroidBackend(false),
-          remote_form_changes_received),
-      std::move(sync_enabled_or_disabled_cb),
-      base::BindOnce(pending_initialization_calls));
-
-  android_backend_->InitBackend(
-      affiliated_match_helper,
-      base::BindRepeating(
-          &PasswordStoreProxyBackend::OnRemoteFormChangesReceived,
-          weak_ptr_factory_.GetWeakPtr(),
-          CallbackOriginatesFromAndroidBackend(true),
-          std::move(remote_form_changes_received)),
-      base::NullCallback(), base::BindOnce(pending_initialization_calls));
-}
-
-void PasswordStoreProxyBackend::Shutdown(base::OnceClosure shutdown_completed) {
-  weak_ptr_factory_.InvalidateWeakPtrs();
-  base::RepeatingClosure pending_shutdown_calls = base::BarrierClosure(
-      /*num_closures=*/2, std::move(shutdown_completed));
-  android_backend_->Shutdown(pending_shutdown_calls);
-  built_in_backend_->Shutdown(pending_shutdown_calls);
-  android_backend_.reset();
-  built_in_backend_.reset();
-}
-
-bool PasswordStoreProxyBackend::IsAbleToSavePasswords() {
-  // shadow_backend()->IsAbleToSavePasswords() doesn't matter because it's a
-  // fallback.
-  return main_backend()->IsAbleToSavePasswords();
-}
-void PasswordStoreProxyBackend::GetAllLoginsAsync(LoginsOrErrorReply callback) {
-  main_backend()->GetAllLoginsAsync(std::move(callback));
-}
-
-void PasswordStoreProxyBackend::GetAllLoginsWithAffiliationAndBrandingAsync(
-    LoginsOrErrorReply callback) {
-  main_backend()->GetAllLoginsWithAffiliationAndBrandingAsync(
-      std::move(callback));
-}
-
-void PasswordStoreProxyBackend::GetAutofillableLoginsAsync(
-    LoginsOrErrorReply callback) {
-  main_backend()->GetAutofillableLoginsAsync(std::move(callback));
-}
-
-void PasswordStoreProxyBackend::FillMatchingLoginsAsync(
-    LoginsOrErrorReply callback,
-    bool include_psl,
-    const std::vector<PasswordFormDigest>& forms) {
-  main_backend()->FillMatchingLoginsAsync(std::move(callback), include_psl,
-                                          forms);
-}
-
-void PasswordStoreProxyBackend::GetGroupedMatchingLoginsAsync(
-    const PasswordFormDigest& form_digest,
-    LoginsOrErrorReply callback) {
-  main_backend()->GetGroupedMatchingLoginsAsync(form_digest,
-                                                std::move(callback));
-}
-
-void PasswordStoreProxyBackend::AddLoginAsync(
-    const PasswordForm& form,
-    PasswordChangesOrErrorReply callback) {
-  PasswordChangesOrErrorReply result_callback;
-  main_backend()->AddLoginAsync(form, std::move(callback));
-}
-
-void PasswordStoreProxyBackend::UpdateLoginAsync(
-    const PasswordForm& form,
-    PasswordChangesOrErrorReply callback) {
-  PasswordChangesOrErrorReply result_callback;
-  main_backend()->UpdateLoginAsync(form, std::move(callback));
-}
-
-void PasswordStoreProxyBackend::RemoveLoginAsync(
-    const base::Location& location,
-    const PasswordForm& form,
-    PasswordChangesOrErrorReply callback) {
-  main_backend()->RemoveLoginAsync(location, form, std::move(callback));
-  if (UsesAndroidBackendAsMainBackend()) {
-    shadow_backend()->RemoveLoginAsync(location, form, base::DoNothing());
-  }
-}
-
-void PasswordStoreProxyBackend::RemoveLoginsCreatedBetweenAsync(
-    const base::Location& location,
-    base::Time delete_begin,
-    base::Time delete_end,
-    base::OnceCallback<void(bool)> sync_completion,
-    PasswordChangesOrErrorReply callback) {
-  main_backend()->RemoveLoginsCreatedBetweenAsync(
-      location, delete_begin, delete_end, base::NullCallback(),
-      std::move(callback));
-  if (UsesAndroidBackendAsMainBackend()) {
-    shadow_backend()->RemoveLoginsCreatedBetweenAsync(
-        location, std::move(delete_begin), std::move(delete_end),
-        base::NullCallback(), base::DoNothing());
-  }
-}
-
-void PasswordStoreProxyBackend::DisableAutoSignInForOriginsAsync(
-    const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
-    base::OnceClosure completion) {
-  // TODO(crbug.com/40208332): Implement error handling, when actual
-  // store changes will be received from the store.
-  main_backend()->DisableAutoSignInForOriginsAsync(origin_filter,
-                                                   std::move(completion));
-}
-
-SmartBubbleStatsStore* PasswordStoreProxyBackend::GetSmartBubbleStatsStore() {
-  return main_backend()->GetSmartBubbleStatsStore();
-}
-
-std::unique_ptr<syncer::DataTypeControllerDelegate>
-PasswordStoreProxyBackend::CreateSyncControllerDelegate() {
-  return built_in_backend_->CreateSyncControllerDelegate();
-}
-
-void PasswordStoreProxyBackend::OnSyncServiceInitialized(
-    syncer::SyncService* sync_service) {
-  sync_service_ = sync_service;
-  sync_service_->AddObserver(this);
-  android_backend_->OnSyncServiceInitialized(sync_service);
-  MaybeClearBuiltInBackend();
-
-  if (!password_manager::sync_util::HasChosenToSyncPasswords(sync_service_)) {
-    // Reset initial UPM migration if password sync is disabled.
-    prefs_->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                       0);
-  }
-}
-
-base::WeakPtr<PasswordStoreBackend> PasswordStoreProxyBackend::AsWeakPtr() {
-  return weak_ptr_factory_.GetWeakPtr();
-}
-
-PasswordStoreBackend* PasswordStoreProxyBackend::main_backend() {
-  return UsesAndroidBackendAsMainBackend() ? android_backend_.get()
-                                           : built_in_backend_.get();
-}
-
-PasswordStoreBackend* PasswordStoreProxyBackend::shadow_backend() {
-  return UsesAndroidBackendAsMainBackend() ? built_in_backend_.get()
-                                           : android_backend_.get();
-}
-
-void PasswordStoreProxyBackend::OnStateChanged(syncer::SyncService* sync) {
-  if (!password_manager::sync_util::HasChosenToSyncPasswords(sync_service_)) {
-    // Reset initial UPM migration if password sync is disabled.
-    prefs_->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                       0);
-  }
-}
-
-void PasswordStoreProxyBackend::OnSyncShutdown(
-    syncer::SyncService* sync_service) {
-  sync_service->RemoveObserver(this);
-  sync_service_ = nullptr;
-}
-
-void PasswordStoreProxyBackend::OnRemoteFormChangesReceived(
-    CallbackOriginatesFromAndroidBackend originates_from_android,
-    RemoteChangesReceived remote_form_changes_received,
-    std::optional<PasswordStoreChangeList> changes) {
-  // `remote_form_changes_received` is used to inform observers about changes in
-  // the backend. This check guarantees observers are informed only about
-  // changes in the main backend.
-  if (originates_from_android.value() == UsesAndroidBackendAsMainBackend()) {
-    remote_form_changes_received.Run(std::move(changes));
-  }
-}
-
-bool PasswordStoreProxyBackend::UsesAndroidBackendAsMainBackend() {
-  CHECK(sync_service_);
-  if (!password_manager::sync_util::HasChosenToSyncPasswords(sync_service_)) {
-    return false;
-  }
-
-  // If there are no passwords in the `LoginDatabase` UPM can be enabled
-  // regardless of other factors since if there are no passwords no migration is
-  // required.
-  if (prefs_->GetBoolean(prefs::kEmptyProfileStoreLoginDatabase)) {
-    return true;
-  }
-
-  // There are passwords in the `LoginDatabase`. In order to ensure that those
-  // passwords are available in the `android_backend_` the user has to not be
-  // unrolled and has to have finished the initial migration.
-  if (prefs_->GetBoolean(
-          prefs::kUnenrolledFromGoogleMobileServicesDueToErrors) ||
-      prefs_->GetInteger(
-          prefs::kCurrentMigrationVersionToGoogleMobileServices) == 0) {
-    return false;
-  }
-
-  return true;
-}
-
-void PasswordStoreProxyBackend::MaybeClearBuiltInBackend() {
-  CHECK(!password_manager::UsesSplitStoresAndUPMForLocal(prefs_));
-
-  // Don't do anything if password syncing is not enabled.
-  if (!password_manager::sync_util::HasChosenToSyncPasswords(sync_service_)) {
-    return;
-  }
-
-  // Don't do anything if the user didn't complete initial UPM migration or was
-  // unenrolled in the past.
-  if (prefs_->GetInteger(
-          prefs::kCurrentMigrationVersionToGoogleMobileServices) == 0 ||
-      prefs_->GetBoolean(
-          prefs::kUnenrolledFromGoogleMobileServicesDueToErrors)) {
-    return;
-  }
-
-  built_in_backend_->RemoveLoginsCreatedBetweenAsync(
-      FROM_HERE, base::Time(), base::Time::Max(), base::NullCallback(),
-      base::BindOnce(&RecordPasswordDeletionResult));
-}
-
-}  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_proxy_backend.h b/chrome/browser/password_manager/android/password_store_proxy_backend.h
deleted file mode 100644
index 3957d17..0000000
--- a/chrome/browser/password_manager/android/password_store_proxy_backend.h
+++ /dev/null
@@ -1,120 +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.
-
-#ifndef CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_PROXY_BACKEND_H_
-#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_PROXY_BACKEND_H_
-
-#include <memory>
-#include <optional>
-
-#include "base/functional/callback_forward.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/types/strong_alias.h"
-#include "components/password_manager/core/browser/password_store/password_store.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_change.h"
-#include "components/sync/service/sync_service.h"
-#include "components/sync/service/sync_service_observer.h"
-
-class PrefService;
-
-namespace password_manager {
-
-// This backend forwards requests to two backends in order to compare and record
-// their results and time differences. The main backend fulfills the  request
-// while the shadow backend is only queried to record shadow traffic.
-class PasswordStoreProxyBackend final : public PasswordStoreBackend,
-                                        public syncer::SyncServiceObserver {
- public:
-  // `built_in_backend` and `android_backend` must not be null and must outlive
-  // this object as long as Shutdown() is not called.
-  PasswordStoreProxyBackend(
-      std::unique_ptr<PasswordStoreBackend> built_in_backend,
-      std::unique_ptr<PasswordStoreBackend> android_backend,
-      PrefService* prefs);
-  PasswordStoreProxyBackend(const PasswordStoreProxyBackend&) = delete;
-  PasswordStoreProxyBackend(PasswordStoreProxyBackend&&) = delete;
-  PasswordStoreProxyBackend& operator=(const PasswordStoreProxyBackend&) =
-      delete;
-  PasswordStoreProxyBackend& operator=(PasswordStoreProxyBackend&&) = delete;
-  ~PasswordStoreProxyBackend() override;
-
- private:
-  using CallbackOriginatesFromAndroidBackend =
-      base::StrongAlias<struct CallbackOriginatesFromAndroidBackendTag, bool>;
-
-  // Implements PasswordStoreBackend interface.
-  void InitBackend(AffiliatedMatchHelper* affiliated_match_helper,
-                   RemoteChangesReceived remote_form_changes_received,
-                   base::RepeatingClosure sync_enabled_or_disabled_cb,
-                   base::OnceCallback<void(bool)> completion) override;
-  void Shutdown(base::OnceClosure shutdown_completed) override;
-  bool IsAbleToSavePasswords() override;
-  void GetAllLoginsAsync(LoginsOrErrorReply callback) override;
-  void GetAllLoginsWithAffiliationAndBrandingAsync(
-      LoginsOrErrorReply callback) override;
-  void GetAutofillableLoginsAsync(LoginsOrErrorReply callback) override;
-  void FillMatchingLoginsAsync(
-      LoginsOrErrorReply callback,
-      bool include_psl,
-      const std::vector<PasswordFormDigest>& forms) override;
-  void GetGroupedMatchingLoginsAsync(const PasswordFormDigest& form_digest,
-                                     LoginsOrErrorReply callback) override;
-  void AddLoginAsync(const PasswordForm& form,
-                     PasswordChangesOrErrorReply callback) override;
-  void UpdateLoginAsync(const PasswordForm& form,
-                        PasswordChangesOrErrorReply callback) override;
-  void RemoveLoginAsync(const base::Location& location,
-                        const PasswordForm& form,
-                        PasswordChangesOrErrorReply callback) override;
-  void RemoveLoginsCreatedBetweenAsync(
-      const base::Location& location,
-      base::Time delete_begin,
-      base::Time delete_end,
-      base::OnceCallback<void(bool)> sync_completion,
-      PasswordChangesOrErrorReply callback) override;
-  void DisableAutoSignInForOriginsAsync(
-      const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
-      base::OnceClosure completion) override;
-  SmartBubbleStatsStore* GetSmartBubbleStatsStore() override;
-  std::unique_ptr<syncer::DataTypeControllerDelegate>
-  CreateSyncControllerDelegate() override;
-  void OnSyncServiceInitialized(syncer::SyncService* sync_service) override;
-  base::WeakPtr<PasswordStoreBackend> AsWeakPtr() override;
-
-  // syncer::SyncServiceObserver:
-  void OnStateChanged(syncer::SyncService* sync) override;
-  void OnSyncShutdown(syncer::SyncService* sync_service) override;
-
-  // Forwards the (possible) forms changes caused by a remote event to the
-  // main backend.
-  void OnRemoteFormChangesReceived(
-      CallbackOriginatesFromAndroidBackend originatesFromAndroid,
-      RemoteChangesReceived remote_form_changes_received,
-      std::optional<PasswordStoreChangeList> changes);
-
-  // Helper used to determine on which backend to run operations.
-  bool UsesAndroidBackendAsMainBackend();
-
-  // Clears all passwords from `built_in_backend_` if all conditions bellow are
-  // satisfied:
-  // - Password sync is enabled
-  // - initial UPM migration was finished and there was no unenrollment
-  void MaybeClearBuiltInBackend();
-
-  PasswordStoreBackend* main_backend();
-  PasswordStoreBackend* shadow_backend();
-
-  std::unique_ptr<PasswordStoreBackend> built_in_backend_;
-  std::unique_ptr<PasswordStoreBackend> android_backend_;
-  raw_ptr<PrefService> const prefs_ = nullptr;
-  raw_ptr<syncer::SyncService> sync_service_ = nullptr;
-
-  base::WeakPtrFactory<PasswordStoreProxyBackend> weak_ptr_factory_{this};
-};
-
-}  // namespace password_manager
-
-#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_STORE_PROXY_BACKEND_H_
diff --git a/chrome/browser/password_manager/android/password_store_proxy_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_proxy_backend_unittest.cc
deleted file mode 100644
index 222699e..0000000
--- a/chrome/browser/password_manager/android/password_store_proxy_backend_unittest.cc
+++ /dev/null
@@ -1,667 +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 "chrome/browser/password_manager/android/password_store_proxy_backend.h"
-
-#include <memory>
-#include <utility>
-#include <variant>
-#include <vector>
-
-#include "base/functional/callback.h"
-#include "base/functional/callback_helpers.h"
-#include "base/strings/strcat.h"
-#include "base/test/gmock_callback_support.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
-#include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/password_form.h"
-#include "components/password_manager/core/browser/password_form_digest.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "components/password_manager/core/browser/password_store/mock_password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend.h"
-#include "components/password_manager/core/browser/password_store/password_store_backend_error.h"
-#include "components/password_manager/core/browser/password_store/password_store_change.h"
-#include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/sync/test/test_sync_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace password_manager {
-namespace {
-
-using ::testing::_;
-using ::testing::AnyNumber;
-using ::testing::AtMost;
-using ::testing::ElementsAreArray;
-using ::testing::Eq;
-using ::testing::Invoke;
-using ::testing::Optional;
-using ::testing::Pointer;
-using ::testing::Return;
-using ::testing::SaveArg;
-using ::testing::StrictMock;
-using ::testing::VariantWith;
-using ::testing::WithArg;
-using Type = PasswordStoreChange::Type;
-using RemoveChangesReceived = PasswordStoreBackend::RemoteChangesReceived;
-
-PasswordForm CreateTestForm() {
-  PasswordForm form;
-  form.username_value = u"Todd Tester";
-  form.password_value = u"S3cr3t";
-  form.url = GURL(u"https://example.com");
-  form.match_type = PasswordForm::MatchType::kExact;
-  return form;
-}
-
-std::vector<PasswordForm> CreateTestLogins() {
-  std::vector<PasswordForm> forms = {
-      CreateEntry("Todd Tester", "S3cr3t", GURL(u"https://example.com"),
-                  PasswordForm::MatchType::kExact),
-      CreateEntry("Marcus McSpartanGregor", "S0m3th1ngCr34t1v3",
-                  GURL(u"https://m.example.com"),
-                  PasswordForm::MatchType::kPSL)};
-  return forms;
-}
-
-bool FilterNoUrl(const GURL& gurl) {
-  return true;
-}
-
-MATCHER_P(PasswordChangesAre, expectations, "") {
-  if (std::holds_alternative<PasswordStoreBackendError>(arg)) {
-    return false;
-  }
-
-  auto changes = std::get<PasswordChanges>(arg);
-  if (!changes.has_value()) {
-    return false;
-  }
-
-  return changes.value() == expectations;
-}
-
-}  // namespace
-
-class PasswordStoreProxyBackendBaseTest : public testing::Test {
- protected:
-  PasswordStoreProxyBackendBaseTest() {
-    prefs_.registry()->RegisterIntegerPref(
-        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kUnenrolledFromGoogleMobileServicesDueToErrors, false);
-    prefs_.registry()->RegisterIntegerPref(
-        password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kEmptyProfileStoreLoginDatabase, true);
-  }
-
-  void SetUp() override { proxy_backend_ = CreateProxyBackend(); }
-
-  std::unique_ptr<PasswordStoreProxyBackend> CreateProxyBackend() {
-    auto built_in_backend =
-        std::make_unique<StrictMock<MockPasswordStoreBackend>>();
-    auto android_backend =
-        std::make_unique<StrictMock<MockPasswordStoreBackend>>();
-    built_in_backend_ = built_in_backend.get();
-    android_backend_ = android_backend.get();
-    return std::make_unique<PasswordStoreProxyBackend>(
-        std::move(built_in_backend), std::move(android_backend), &prefs_);
-  }
-
-  void TearDown() override {
-    EXPECT_CALL(*android_backend_, Shutdown(_));
-    EXPECT_CALL(*built_in_backend_, Shutdown(_));
-    PasswordStoreBackend* backend = proxy_backend_.get();  // Will be destroyed.
-    backend->Shutdown(base::DoNothing());
-    proxy_backend_.reset();
-  }
-
-  void EnablePasswordSync() {
-    sync_service_.GetUserSettings()->SetSelectedTypes(
-        /*sync_everything=*/false, {syncer::UserSelectableType::kPasswords});
-    sync_service_.FireStateChanged();
-  }
-
-  void DisablePasswordSync() {
-    sync_service_.GetUserSettings()->SetSelectedTypes(
-        /*sync_everything=*/false, /*types=*/{});
-    sync_service_.FireStateChanged();
-  }
-
-  PasswordStoreBackend& proxy_backend() { return *proxy_backend_; }
-  MockPasswordStoreBackend& built_in_backend() { return *built_in_backend_; }
-  MockPasswordStoreBackend& android_backend() { return *android_backend_; }
-  TestingPrefServiceSimple* prefs() { return &prefs_; }
-  syncer::TestSyncService* sync_service() { return &sync_service_; }
-
-  raw_ptr<StrictMock<MockPasswordStoreBackend>> built_in_backend_;
-  raw_ptr<StrictMock<MockPasswordStoreBackend>> android_backend_;
-
- private:
-  TestingPrefServiceSimple prefs_;
-  std::unique_ptr<PasswordStoreProxyBackend> proxy_backend_;
-  syncer::TestSyncService sync_service_;
-};
-
-TEST_F(PasswordStoreProxyBackendBaseTest, CallCompletionCallbackAfterInit) {
-  base::MockCallback<base::OnceCallback<void(bool)>> completion_callback;
-
-  // Both backends need to be invoked for a successful completion call.
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(
-          WithArg<3>(Invoke([](base::OnceCallback<void(bool)> reply) -> void {
-            std::move(reply).Run(true);
-          })));
-
-  base::OnceCallback<void(bool)> captured_android_backend_reply;
-  EXPECT_CALL(android_backend(), InitBackend)
-      .WillOnce(
-          WithArg<3>(Invoke([&](base::OnceCallback<void(bool)> reply) -> void {
-            captured_android_backend_reply = std::move(reply);
-          })));
-
-  proxy_backend().InitBackend(nullptr, base::DoNothing(), base::DoNothing(),
-                              completion_callback.Get());
-  // The android backend requires the sync service to be initialized before
-  // signaling that the backend initialization is complete.
-  EXPECT_CALL(completion_callback, Run(true));
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()))
-      .WillOnce(Invoke([&]() -> void {
-        std::move(captured_android_backend_reply).Run(true);
-      }));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       CallCompletionWithFailureForAnyError) {
-  base::MockCallback<base::OnceCallback<void(bool)>> completion_callback;
-
-  // If one backend fails to initialize, the result of the second is
-  // irrelevant.
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(
-          WithArg<3>(Invoke([](base::OnceCallback<void(bool)> reply) -> void {
-            std::move(reply).Run(false);
-          })));
-  base::OnceCallback<void(bool)> captured_android_backend_reply;
-  EXPECT_CALL(android_backend(), InitBackend)
-      .Times(AtMost(1))
-      .WillOnce(
-          WithArg<3>(Invoke([&](base::OnceCallback<void(bool)> reply) -> void {
-            captured_android_backend_reply = std::move(reply);
-          })));
-
-  proxy_backend().InitBackend(nullptr, base::DoNothing(), base::DoNothing(),
-                              completion_callback.Get());
-  // The android backend requires the sync service to be initialized before
-  // signaling that the backend initialization is complete.
-  EXPECT_CALL(completion_callback, Run(false));
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()))
-      .WillOnce(Invoke([&]() -> void {
-        std::move(captured_android_backend_reply).Run(false);
-      }));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       ProfileNoLocalSupportCallRemoteChangesOnlyForMainBackend) {
-  base::MockCallback<RemoveChangesReceived> original_callback;
-
-  // Both backends receive a callback that they trigger for new remote changes.
-  RemoveChangesReceived built_in_remote_changes_callback;
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(SaveArg<1>(&built_in_remote_changes_callback));
-  RemoveChangesReceived android_remote_changes_callback;
-  EXPECT_CALL(android_backend(), InitBackend)
-      .WillOnce(SaveArg<1>(&android_remote_changes_callback));
-  proxy_backend().InitBackend(nullptr, original_callback.Get(),
-                              base::DoNothing(), base::DoNothing());
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-
-  // With sync enabled, only the android backend calls the original callback.
-  EnablePasswordSync();
-  EXPECT_CALL(original_callback, Run);
-  android_remote_changes_callback.Run(std::nullopt);
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-
-  EXPECT_CALL(original_callback, Run).Times(0);
-  built_in_remote_changes_callback.Run(std::nullopt);
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-
-  // As soon as sync is disabled, only the built-in backend calls the original
-  // callback. The callbacks are stable. No new Init call is necessary.
-  DisablePasswordSync();
-
-  EXPECT_CALL(original_callback, Run).Times(0);
-  android_remote_changes_callback.Run(std::nullopt);
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-
-  EXPECT_CALL(original_callback, Run);
-  built_in_remote_changes_callback.Run(std::nullopt);
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       ProfileNoLocalSupportCallSyncCallbackForTheBuiltInBackend) {
-  base::MockCallback<base::RepeatingClosure> original_callback;
-
-  // Both backends receive a callback that they trigger for new remote changes.
-  base::RepeatingClosure built_in_sync_callback;
-  EXPECT_CALL(built_in_backend(), InitBackend)
-      .WillOnce(SaveArg<2>(&built_in_sync_callback));
-  EXPECT_CALL(android_backend(), InitBackend);
-  proxy_backend().InitBackend(nullptr, base::DoNothing(),
-                              original_callback.Get(), base::DoNothing());
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-
-  // With sync enabled, only the built-in backend calls the original callback.
-  EnablePasswordSync();
-
-  EXPECT_CALL(original_callback, Run);
-  built_in_sync_callback.Run();
-  testing::Mock::VerifyAndClearExpectations(&original_callback);
-
-  // With sync is disabled, the built-in backend remains the only to call the
-  // original callback.
-  DisablePasswordSync();
-
-  EXPECT_CALL(original_callback, Run);
-  built_in_sync_callback.Run();
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest, BuiltInBackendClearedOnSyncInit) {
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
-  EnablePasswordSync();
-
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  EXPECT_CALL(built_in_backend(),
-              RemoveLoginsCreatedBetweenAsync(_, base::Time(),
-                                              base::Time::Max(), _, _));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       BuiltInBackendNotClearedOnSyncInit_WhenUnenrolled) {
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
-  prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-                      true);
-  EnablePasswordSync();
-
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  EXPECT_CALL(built_in_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       BuiltInBackendNotClearedOnSyncInit_WhenInitialUPMMigrationNotFinished) {
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-  EnablePasswordSync();
-
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  EXPECT_CALL(built_in_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       BuiltInBackendNotClearedOnSyncInit_WhenSyncDisabled) {
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  EXPECT_CALL(built_in_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       BuiltInBackendClearedOnSyncInit_Metrics) {
-  base::HistogramTester histogram_tester;
-  const char kStatusMetric[] =
-      "PasswordManager.PasswordStoreProxyBackend.PasswordRemovalStatus";
-  const char kCountMetric[] =
-      "PasswordManager.PasswordStoreProxyBackend.RemovedPasswordCount";
-
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
-  EnablePasswordSync();
-
-  PasswordStoreChangeList change_list;
-  change_list.emplace_back(Type::REMOVE, CreateTestForm());
-  change_list.emplace_back(Type::REMOVE, CreateTestForm());
-
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  EXPECT_CALL(built_in_backend(), RemoveLoginsCreatedBetweenAsync(
-                                      _, base::Time(), base::Time::Max(), _, _))
-      .WillOnce(base::test::RunOnceCallback<4>(change_list));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-
-  histogram_tester.ExpectTotalCount(kStatusMetric, 1);
-  histogram_tester.ExpectBucketCount(kStatusMetric, true, 1);
-  histogram_tester.ExpectTotalCount(kCountMetric, 1);
-  histogram_tester.ExpectBucketCount(kCountMetric, change_list.size(), 1);
-}
-
-TEST_F(PasswordStoreProxyBackendBaseTest,
-       InitialUPMMigrationPrefIsResetOnSyncInit) {
-  prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
-  DisablePasswordSync();
-
-  EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-  proxy_backend().OnSyncServiceInitialized(sync_service());
-  EXPECT_EQ(0, prefs()->GetInteger(
-                   prefs::kCurrentMigrationVersionToGoogleMobileServices));
-}
-
-// Holds the conditions affecting UPM eligibility and the backends
-// which should be used for each.
-struct UpmVariationParam {
-  bool is_sync_enabled = false;
-  bool is_unenrolled = false;
-  bool is_login_db_empty = false;
-  bool is_initial_migration_finished = false;
-  bool android_is_main_backend = false;
-};
-
-class PasswordStoreProxyBackendTest
-    : public PasswordStoreProxyBackendBaseTest,
-      public testing::WithParamInterface<UpmVariationParam> {
- public:
-  void SetUp() override {
-    PasswordStoreProxyBackendBaseTest::SetUp();
-
-    if (GetParam().is_sync_enabled) {
-      EnablePasswordSync();
-    } else {
-      DisablePasswordSync();
-    }
-    prefs()->SetBoolean(prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
-                        GetParam().is_unenrolled);
-    prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
-                        GetParam().is_initial_migration_finished ? 1 : 0);
-    prefs()->SetBoolean(prefs::kEmptyProfileStoreLoginDatabase,
-                        GetParam().is_login_db_empty);
-
-    if (GetParam().is_sync_enabled &&
-        GetParam().is_initial_migration_finished && !GetParam().is_unenrolled) {
-      // The login DB should be cleared for healthy syncing users.
-      EXPECT_CALL(built_in_backend(),
-                  RemoveLoginsCreatedBetweenAsync(_, base::Time(),
-                                                  base::Time::Max(), _, _));
-    }
-
-    EXPECT_CALL(android_backend(), InitBackend);
-    EXPECT_CALL(built_in_backend(), InitBackend);
-    proxy_backend().InitBackend(nullptr, base::DoNothing(), base::DoNothing(),
-                                base::DoNothing());
-    EXPECT_CALL(android_backend(), OnSyncServiceInitialized(sync_service()));
-    proxy_backend().OnSyncServiceInitialized(sync_service());
-  }
-
-  MockPasswordStoreBackend& main_backend() {
-    return GetParam().android_is_main_backend ? android_backend()
-                                              : built_in_backend();
-  }
-
-  MockPasswordStoreBackend& shadow_backend() {
-    return GetParam().android_is_main_backend ? built_in_backend()
-                                              : android_backend();
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_P(PasswordStoreProxyBackendTest, UseMainBackendToGetAllLoginsAsync) {
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  EXPECT_CALL(
-      mock_reply,
-      Run(VariantWith<LoginsResult>(ElementsAreArray(CreateTestLogins()))));
-
-  EXPECT_CALL(main_backend(), GetAllLoginsAsync)
-      .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
-        std::move(reply).Run(CreateTestLogins());
-      })));
-  EXPECT_CALL(shadow_backend(), GetAllLoginsAsync).Times(0);
-
-  proxy_backend().GetAllLoginsAsync(mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest,
-       UseMainBackendToGetAutofillableLoginsAsync) {
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  EXPECT_CALL(
-      mock_reply,
-      Run(VariantWith<LoginsResult>(ElementsAreArray(CreateTestLogins()))));
-
-  EXPECT_CALL(main_backend(), GetAutofillableLoginsAsync)
-      .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
-        std::move(reply).Run(CreateTestLogins());
-      })));
-  EXPECT_CALL(shadow_backend(), GetAutofillableLoginsAsync).Times(0);
-
-  proxy_backend().GetAutofillableLoginsAsync(mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest, UseMainBackendToFillMatchingLoginsAsync) {
-  base::MockCallback<LoginsOrErrorReply> mock_reply;
-  EXPECT_CALL(
-      mock_reply,
-      Run(VariantWith<LoginsResult>(ElementsAreArray(CreateTestLogins()))));
-
-  EXPECT_CALL(main_backend(), FillMatchingLoginsAsync)
-      .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
-        std::move(reply).Run(CreateTestLogins());
-      })));
-  EXPECT_CALL(shadow_backend(), FillMatchingLoginsAsync).Times(0);
-
-  proxy_backend().FillMatchingLoginsAsync(mock_reply.Get(),
-                                          /*include_psl=*/false,
-                                          std::vector<PasswordFormDigest>());
-}
-
-TEST_P(PasswordStoreProxyBackendTest, UseMainBackendToAddLoginAsync) {
-  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
-  PasswordForm form = CreateTestForm();
-  PasswordStoreChangeList change_list;
-  change_list.push_back(PasswordStoreChange(Type::ADD, form));
-  EXPECT_CALL(mock_reply,
-              Run(VariantWith<PasswordChanges>(Optional(change_list))));
-
-  EXPECT_CALL(main_backend(), AddLoginAsync(Eq(form), _))
-      .WillOnce(WithArg<1>(
-          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
-            std::move(reply).Run(change_list);
-          })));
-  EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(0);
-
-  proxy_backend().AddLoginAsync(form, mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest, UseMainBackendToUpdateLoginAsync) {
-  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
-  PasswordForm form = CreateTestForm();
-  PasswordStoreChangeList change_list;
-  change_list.push_back(PasswordStoreChange(Type::UPDATE, form));
-  EXPECT_CALL(mock_reply,
-              Run(VariantWith<PasswordChanges>(Optional(change_list))));
-
-  EXPECT_CALL(main_backend(), UpdateLoginAsync(Eq(form), _))
-      .WillOnce(WithArg<1>(
-          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
-            std::move(reply).Run(change_list);
-          })));
-  EXPECT_CALL(shadow_backend(), UpdateLoginAsync).Times(0);
-
-  proxy_backend().UpdateLoginAsync(form, mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest, UseBothBackendsToRemoveLoginAsyncIfUPM) {
-  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
-  PasswordForm form = CreateTestForm();
-  PasswordStoreChangeList change_list;
-  change_list.push_back(PasswordStoreChange(Type::REMOVE, form));
-  EXPECT_CALL(mock_reply,
-              Run(VariantWith<PasswordChanges>(Optional(change_list))));
-
-  EXPECT_CALL(main_backend(), RemoveLoginAsync(_, Eq(form), _))
-      .WillOnce(WithArg<2>(
-          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
-            std::move(reply).Run(change_list);
-          })));
-
-  // The shadow backend should only be called to remove logins if the main
-  // backend is the android backend, to ensure the login db passwords are
-  // also removed.
-  EXPECT_CALL(shadow_backend(), RemoveLoginAsync(_, Eq(form), _))
-      .Times(GetParam().android_is_main_backend ? 1 : 0);
-  proxy_backend().RemoveLoginAsync(FROM_HERE, form, mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest,
-       UseBothBackendsToRemoveLoginsCreatedBetweenAsyncIfUPM) {
-  base::Time kStart = base::Time::FromTimeT(111111);
-  base::Time kEnd = base::Time::FromTimeT(22222222);
-  base::MockCallback<PasswordChangesOrErrorReply> mock_reply;
-  PasswordStoreChangeList change_list;
-  change_list.push_back(PasswordStoreChange(Type::REMOVE, CreateTestForm()));
-  EXPECT_CALL(mock_reply,
-              Run(VariantWith<PasswordChanges>(Optional(change_list))));
-
-  EXPECT_CALL(main_backend(),
-              RemoveLoginsCreatedBetweenAsync(_, Eq(kStart), Eq(kEnd), _, _))
-      .WillOnce(WithArg<4>(
-          Invoke([&change_list](PasswordChangesOrErrorReply reply) -> void {
-            std::move(reply).Run(change_list);
-          })));
-  EXPECT_CALL(shadow_backend(),
-              RemoveLoginsCreatedBetweenAsync(_, Eq(kStart), Eq(kEnd), _, _))
-      .Times(GetParam().android_is_main_backend ? 1 : 0);
-  proxy_backend().RemoveLoginsCreatedBetweenAsync(
-      FROM_HERE, kStart, kEnd, base::NullCallback(), mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest,
-       UseMainBackendToDisableAutoSignInForOriginsAsync) {
-  base::MockCallback<base::OnceClosure> mock_reply;
-  EXPECT_CALL(mock_reply, Run);
-  EXPECT_CALL(main_backend(), DisableAutoSignInForOriginsAsync)
-      .WillOnce(WithArg<1>(
-          Invoke([](base::OnceClosure reply) { std::move(reply).Run(); })));
-  EXPECT_CALL(shadow_backend(), DisableAutoSignInForOriginsAsync).Times(0);
-  proxy_backend().DisableAutoSignInForOriginsAsync(
-      base::BindRepeating(&FilterNoUrl), mock_reply.Get());
-}
-
-TEST_P(PasswordStoreProxyBackendTest,
-       UseMainBackendToGetSmartBubbleStatsStore) {
-  EXPECT_CALL(main_backend(), GetSmartBubbleStatsStore);
-  EXPECT_CALL(shadow_backend(), GetSmartBubbleStatsStore).Times(0);
-  proxy_backend().GetSmartBubbleStatsStore();
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    PasswordStoreProxyBackendBaseTest,
-    PasswordStoreProxyBackendTest,
-    // PasswordStoreProxyBackend is created only for `ProfilePasswordStore` when
-    // `UseUpmLocalAndSeparateStoresState` is `kOff`. In this configuration
-    // there are 5 possible variables which can influence when `android_backend`
-    // is used. All 32 configurations are tested here.
-    testing::Values(UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = true},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = false,
-                                      .android_is_main_backend = true},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = true},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = false,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = false,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = true},
-                    UpmVariationParam{.is_sync_enabled = false,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = false},
-                    UpmVariationParam{.is_sync_enabled = true,
-                                      .is_unenrolled = true,
-                                      .is_login_db_empty = true,
-                                      .is_initial_migration_finished = true,
-                                      .android_is_main_backend = true}),
-    [](const ::testing::TestParamInfo<UpmVariationParam>& info) {
-      std::string name;
-      name += info.param.is_sync_enabled ? "Syncing" : "Local";
-      name += info.param.is_unenrolled ? "Unenrolled" : "";
-      name += info.param.is_initial_migration_finished ? "" : "NotMigrated";
-      name += info.param.is_login_db_empty ? "EmptyDB" : "";
-      return name;
-    });
-
-}  // namespace password_manager
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
index b9171a8..e759ed6 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
@@ -16,7 +16,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/android/resource_mapper.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/profiles/profile.h"
@@ -51,21 +50,6 @@
 constexpr base::TimeDelta kUpdateGMSCoreMessageDisplayDelay =
     base::Milliseconds(500);
 
-void TryToShowAccessLossWarning(content::WebContents* web_contents,
-                                PasswordAccessLossWarningBridge* bridge) {
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  PrefService* prefs = profile->GetPrefs();
-  if (profile && bridge->ShouldShowAccessLossNoticeSheet(
-                     prefs, /*called_at_startup=*/false)) {
-    bridge->MaybeShowAccessLossNoticeSheet(
-        prefs, web_contents->GetTopLevelNativeWindow(), profile,
-        /*called_at_startup=*/false,
-        password_manager_android_util::PasswordAccessLossWarningTriggers::
-            kPasswordSaveUpdateMessage);
-  }
-}
-
 }  // namespace
 
 SaveUpdatePasswordMessageDelegate::SaveUpdatePasswordMessageDelegate()
@@ -75,18 +59,14 @@
 SaveUpdatePasswordMessageDelegate::SaveUpdatePasswordMessageDelegate(
     PasswordEditDialogFactory password_edit_dialog_factory)
     : password_edit_dialog_factory_(std::move(password_edit_dialog_factory)),
-      device_lock_bridge_(std::make_unique<DeviceLockBridge>()),
-      access_loss_bridge_(
-          std::make_unique<PasswordAccessLossWarningBridgeImpl>()) {}
+      device_lock_bridge_(std::make_unique<DeviceLockBridge>()) {}
 
 SaveUpdatePasswordMessageDelegate::SaveUpdatePasswordMessageDelegate(
     base::PassKey<class SaveUpdatePasswordMessageDelegateTest>,
     PasswordEditDialogFactory password_edit_dialog_factory,
-    std::unique_ptr<DeviceLockBridge> device_lock_bridge,
-    std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_bridge)
+    std::unique_ptr<DeviceLockBridge> device_lock_bridge)
     : SaveUpdatePasswordMessageDelegate(password_edit_dialog_factory) {
   device_lock_bridge_ = std::move(device_lock_bridge);
-  access_loss_bridge_ = std::move(access_loss_bridge);
 }
 
 SaveUpdatePasswordMessageDelegate::~SaveUpdatePasswordMessageDelegate() {
@@ -345,7 +325,6 @@
             &SaveUpdatePasswordMessageDelegate::MaybeNudgeToUpdateGmsCore,
             weak_ptr_factory_.GetWeakPtr()),
         kUpdateGMSCoreMessageDisplayDelay);
-    TryToShowAccessLossWarning(web_contents_, access_loss_bridge_.get());
   }
   ClearState();
 }
@@ -404,9 +383,6 @@
   // callback.
   if (!(device_lock_bridge_->ShouldShowDeviceLockUi() &&
         web_contents_->GetNativeView()->GetWindowAndroid())) {
-    if (dismiss_reason == messages::DismissReason::PRIMARY_ACTION) {
-      TryToShowAccessLossWarning(web_contents_, access_loss_bridge_.get());
-    }
     ClearState();
   }
 }
@@ -435,7 +411,6 @@
   // callback.
   if (!(device_lock_bridge_->ShouldShowDeviceLockUi() &&
         web_contents_->GetNativeView()->GetWindowAndroid())) {
-    TryToShowAccessLossWarning(web_contents_, access_loss_bridge_.get());
     ClearState();
   }
 }
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.h b/chrome/browser/password_manager/android/save_update_password_message_delegate.h
index d894a71..41cdaa0 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate.h
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.h
@@ -12,7 +12,6 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/passwords/manage_passwords_state.h"
 #include "components/browser_ui/device_lock/android/device_lock_bridge.h"
@@ -50,8 +49,7 @@
   SaveUpdatePasswordMessageDelegate(
       base::PassKey<class SaveUpdatePasswordMessageDelegateTest>,
       PasswordEditDialogFactory password_edit_dialog_factory,
-      std::unique_ptr<DeviceLockBridge> device_lock_bridge,
-      std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_bridge);
+      std::unique_ptr<DeviceLockBridge> device_lock_bridge);
 
   // Displays a "Save password" message for current |web_contents| and
   // |form_to_save|.
@@ -152,7 +150,6 @@
   std::unique_ptr<PasswordEditDialog> password_edit_dialog_;
 
   std::unique_ptr<DeviceLockBridge> device_lock_bridge_;
-  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_bridge_;
 
   void SavePassword();
   void SavePasswordAfterDeviceLockUi(bool is_device_lock_set);
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
index 41f2229a..7452a96 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/android/resource_mapper.h"
 #include "chrome/browser/password_edit_dialog/android/password_edit_dialog_bridge_delegate.h"
-#include "chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 #include "chrome/grit/branded_strings.h"
@@ -164,7 +163,6 @@
   void DestroyDelegate();
 
   TestDeviceLockBridge* test_bridge();
-  MockPasswordAccessLossWarningBridge* mock_access_loss_warning_bridge();
   bool is_password_saved();
 
   messages::MessageWrapper* GetMessageWrapper();
@@ -224,7 +222,6 @@
   messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
   std::unique_ptr<MockPasswordEditDialog> mock_password_edit_dialog_;
   raw_ptr<TestDeviceLockBridge> test_bridge_;
-  raw_ptr<MockPasswordAccessLossWarningBridge> mock_access_loss_warning_bridge_;
   std::unique_ptr<SaveUpdatePasswordMessageDelegate> delegate_;
   bool is_password_saved_ = false;
   MockPasswordManagerClient password_manager_client_;
@@ -244,15 +241,12 @@
 
   auto bridge = std::make_unique<TestDeviceLockBridge>();
   test_bridge_ = bridge.get();
-  auto access_loss_bridge =
-      std::make_unique<MockPasswordAccessLossWarningBridge>();
-  mock_access_loss_warning_bridge_ = access_loss_bridge.get();
   delegate_ = std::make_unique<SaveUpdatePasswordMessageDelegate>(
       base::PassKey<class SaveUpdatePasswordMessageDelegateTest>(),
       base::BindRepeating(
           &SaveUpdatePasswordMessageDelegateTest::CreatePasswordEditDialog,
           base::Unretained(this)),
-      std::move(bridge), std::move(access_loss_bridge));
+      std::move(bridge));
 
   messages::MessageDispatcherBridge::SetInstanceForTesting(
       &message_dispatcher_bridge_);
@@ -400,11 +394,6 @@
   return test_bridge_;
 }
 
-MockPasswordAccessLossWarningBridge*
-SaveUpdatePasswordMessageDelegateTest::mock_access_loss_warning_bridge() {
-  return mock_access_loss_warning_bridge_;
-}
-
 bool SaveUpdatePasswordMessageDelegateTest::is_password_saved() {
   return is_password_saved_;
 }
@@ -582,31 +571,6 @@
       password_manager::metrics_util::CLICKED_ACCEPT, 1);
 }
 
-// Tests that the access loss warning will show when the user
-// clicks the "Save" button.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       TriggerAccessLossWarning_OnSaveClicked) {
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
-  EXPECT_CALL(*form_manager, Save());
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false,
-                 /*update_password=*/false);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(
-      *mock_access_loss_warning_bridge(),
-      MaybeShowAccessLossNoticeSheet(
-          profile()->GetPrefs(), _, profile(),
-          /*called_at_startup=*/false,
-          password_manager_android_util::PasswordAccessLossWarningTriggers::
-              kPasswordSaveUpdateMessage));
-  TriggerActionClick();
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-}
-
 // Tests that the message to update GMSCore will show when the user
 // clicks the "Save" button if the GMSCore version is too low to save account
 // passwords.
@@ -657,87 +621,6 @@
   EXPECT_EQ(nullptr, GetMessageWrapper());
 }
 
-// Tests that the password access loss warning will show when the user
-// accepts the password edit dialog.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       TriggerAccessLossWarning_OnSavePasswordDialogAccepted) {
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
-  MockPasswordFormManagerForUI* form_manager_pointer = form_manager.get();
-  MockPasswordEditDialog* mock_dialog = PreparePasswordEditDialog();
-
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false,
-                 /*update_password=*/false);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_dialog, ShowPasswordEditDialog);
-  TriggerPasswordEditDialog(/*update_password=*/false);
-
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*form_manager_pointer, Save());
-  TriggerDialogAcceptedCallback(/*username=*/kUsername,
-                                /*password=*/kPassword);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(
-      *mock_access_loss_warning_bridge(),
-      MaybeShowAccessLossNoticeSheet(
-          profile()->GetPrefs(), _, profile(),
-          /*called_at_startup=*/false,
-          password_manager_android_util::PasswordAccessLossWarningTriggers::
-              kPasswordSaveUpdateMessage));
-  TriggerDialogDismissedCallback(/*dialog_accepted=*/true);
-}
-
-// Tests that the access loss warning will not show when the user
-// dismisses the save password message.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       DontTriggerAccessLossWarning_OnSaveMessageDismissed) {
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true,
-                 /*update_password=*/false);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  DismissMessage(messages::DismissReason::GESTURE);
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-}
-
-// Tests that the access loss warning will show when the user accepts the update
-// password message in case when there is no confirmation dialog.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       TriggerAccessLossWarning_OnUpdatePasswordWithSingleForm) {
-  SetPendingCredentials(kUsername, kPassword);
-  std::vector<PasswordForm> single_form_best_matches = {
-      CreatePasswordForm(kUsername, kPassword)};
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), single_form_best_matches);
-  EXPECT_CALL(*form_manager, Save());
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true,
-                 /*update_password=*/true);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(
-      *mock_access_loss_warning_bridge(),
-      MaybeShowAccessLossNoticeSheet(
-          profile()->GetPrefs(), _, profile(),
-          /*called_at_startup=*/false,
-          password_manager_android_util::PasswordAccessLossWarningTriggers::
-              kPasswordSaveUpdateMessage));
-  TriggerActionClick();
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-}
-
 // Tests that the message to update GMSCore will show when the user accepts the
 // update password message in case when there is no confirmation
 // dialog.
@@ -794,97 +677,6 @@
   EXPECT_EQ(nullptr, GetMessageWrapper());
 }
 
-// Tests that the access loss warning will not show when the user
-// dismisses the update password message.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       DontTriggerAccessLossWarning_OnUpdatePasswordMessageDismissed) {
-  SetPendingCredentials(kUsername, kPassword);
-  std::vector<PasswordForm> single_form_best_matches = {
-      CreatePasswordForm(kUsername, kPassword)};
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), single_form_best_matches);
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true,
-                 /*update_password=*/true);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  DismissMessage(messages::DismissReason::GESTURE);
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-}
-
-// Tests that the access loss warning will show when the user accepts the update
-// password message and the confirmation dialog.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       TriggerAccessLossWarning_OnUpdatePasswordDialogAccepted) {
-  SetPendingCredentials(kUsername, kPassword);
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), two_forms_best_matches());
-  MockPasswordEditDialog* mock_dialog = PreparePasswordEditDialog();
-  EXPECT_CALL(
-      *mock_dialog,
-      ShowPasswordEditDialog(
-          ElementsAre(std::u16string(kUsername), std::u16string(kUsername2)),
-          Eq(kUsername), Eq(kPassword), Eq(kAccountEmail)));
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true,
-                 /*update_password=*/true);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  TriggerActionClick();
-  TriggerDialogAcceptedCallback(/*username=*/kUsername,
-                                /*password=*/kPassword);
-  EXPECT_CALL(
-      *mock_access_loss_warning_bridge(),
-      MaybeShowAccessLossNoticeSheet(
-          profile()->GetPrefs(), _, profile(),
-          /*called_at_startup=*/false,
-          password_manager_android_util::PasswordAccessLossWarningTriggers::
-              kPasswordSaveUpdateMessage));
-  TriggerDialogDismissedCallback(/*dialog_accepted=*/true);
-}
-
-// Tests that the access loss warning will show when the user accepts the
-// update password message and cancels the confirmation dialog.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       TriggerAccessLossWarning_OnUpdatePasswordDialogCanceled) {
-  SetPendingCredentials(kUsername, kPassword);
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), two_forms_best_matches());
-  MockPasswordEditDialog* mock_dialog = PreparePasswordEditDialog();
-  EXPECT_CALL(
-      *mock_dialog,
-      ShowPasswordEditDialog(
-          ElementsAre(std::u16string(kUsername), std::u16string(kUsername2)),
-          Eq(kUsername), Eq(kPassword), Eq(kAccountEmail)));
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true,
-                 /*update_password=*/true);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  TriggerActionClick();
-  EXPECT_CALL(
-      *mock_access_loss_warning_bridge(),
-      MaybeShowAccessLossNoticeSheet(
-          profile()->GetPrefs(), _, profile(),
-          /*called_at_startup=*/false,
-          password_manager_android_util::PasswordAccessLossWarningTriggers::
-              kPasswordSaveUpdateMessage));
-  TriggerDialogDismissedCallback(/*dialog_accepted=*/false);
-}
-
 // Tests that password form is not saved and metrics recorded correctly when the
 // user dismisses the message.
 TEST_F(SaveUpdatePasswordMessageDelegateTest, DontSaveOnDismiss) {
@@ -933,49 +725,6 @@
       password_manager::metrics_util::NO_DIRECT_INTERACTION, 1);
 }
 
-// Tests that the access loss warning will not show when the user lets the save
-// message time out.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       DontTriggerAccessLossWarning_OnSaveMessageAutodismissTimer) {
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false,
-                 /*update_password=*/false);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  DismissMessage(messages::DismissReason::TIMER);
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-}
-
-// Tests that the access loss warning will not show when the user lets the
-// update message time out.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       DontTriggerAccessLossWarning_OnUpdateMessageAutodismissTimer) {
-  SetPendingCredentials(kUsername, kPassword);
-  std::vector<PasswordForm> single_form_best_matches = {
-      CreatePasswordForm(kUsername, kPassword)};
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), single_form_best_matches);
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/true,
-                 /*update_password=*/true);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  DismissMessage(messages::DismissReason::TIMER);
-  EXPECT_EQ(nullptr, GetMessageWrapper());
-}
-
 // Tests that update password message with a single PasswordForm immediately
 // saves the form on Update button tap and doesn't display confirmation dialog.
 TEST_F(SaveUpdatePasswordMessageDelegateTest, UpdatePasswordWithSingleForm) {
@@ -1100,28 +849,6 @@
       password_manager::metrics_util::CLICKED_NEVER, 1);
 }
 
-// Verifies that the access loss warning is not shown after selecting
-// "Never for this site" menu option in the Save message.
-TEST_F(SaveUpdatePasswordMessageDelegateTest,
-       DontTriggerAccessLossWarning_OnNeverSave) {
-  auto form_manager =
-      CreateFormManager(GURL(kDefaultUrl), empty_best_matches());
-  MockPasswordFormManagerForUI* form_manager_pointer = form_manager.get();
-
-  EnqueueMessage(std::move(form_manager), /*user_signed_in=*/false,
-                 /*update_password=*/false);
-  EXPECT_NE(nullptr, GetMessageWrapper());
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  EXPECT_CALL(*form_manager_pointer, Blocklist());
-  TriggerNeverSaveMenuItem();
-}
-
 // Verifies that:
 // 1. Update password dialog is shown after clicking on cog button (secondary
 // action) in the message.
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 31fbb5b..9857d8038 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -144,7 +144,6 @@
 #include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
 #include "chrome/browser/keyboard_accessory/android/password_accessory_controller.h"
 #include "chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/password_manager/android/account_chooser_dialog_android.h"
 #include "chrome/browser/password_manager/android/auto_signin_first_run_dialog_android.h"
 #include "chrome/browser/password_manager/android/auto_signin_prompt_controller.h"
@@ -194,7 +193,6 @@
 #if BUILDFLAG(IS_ANDROID)
 using base::android::BuildInfo;
 using password_manager::CredentialCache;
-using password_manager_android_util::GmsVersionCohort;
 #endif
 
 using autofill::mojom::FocusedFieldType;
@@ -229,20 +227,6 @@
   return url::Origin::Create(url.DeprecatedGetOriginAsURL());
 }
 
-void ShowAccessLossWarning(PrefService* prefs,
-                           base::WeakPtr<content::WebContents> web_contents,
-                           Profile* profile) {
-  if (!web_contents) {
-    return;
-  }
-  PasswordAccessLossWarningBridgeImpl bridge;
-  bridge.MaybeShowAccessLossNoticeSheet(
-      prefs, web_contents->GetTopLevelNativeWindow(), profile,
-      /*called_at_startup=*/true,
-      password_manager_android_util::PasswordAccessLossWarningTriggers::
-          kChromeStartup);
-}
-
 void MaybeShowPostMigrationSheetWrapper(
     base::WeakPtr<content::WebContents> web_contents,
     Profile* profile) {
@@ -1928,16 +1912,6 @@
   autofill_managers_observation_.Observe(
       web_contents, autofill::ScopedAutofillManagersObservation::
                         InitializationPolicy::kObservePreexistingManagers);
-
-#if BUILDFLAG(IS_ANDROID)
-  // This prevents the access loss warning from trying to show on opening new
-  // tabs after the initial attempt to show the sheet on startup.
-  static bool tried_launching_access_loss_warning_on_startup = false;
-  if (!tried_launching_access_loss_warning_on_startup) {
-    tried_launching_access_loss_warning_on_startup = true;
-    TryToShowAccessLossWarningSheet();
-  }
-#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 void ChromePasswordManagerClient::PrimaryPageChanged(content::Page& page) {
@@ -2289,75 +2263,6 @@
       FROM_HERE, base::BindOnce(&MaybeShowPostMigrationSheetWrapper,
                                 web_contents()->GetWeakPtr(), profile_));
 }
-
-void ChromePasswordManagerClient::TryToShowAccessLossWarningSheet() {
-  PasswordAccessLossWarningBridgeImpl bridge;
-  // If the feature is not enabled or it's too early to show the startup warning
-  // sheet, the method ends.
-  if (!bridge.ShouldShowAccessLossNoticeSheet(GetPrefs(),
-                                              /*called_at_startup=*/true)) {
-    return;
-  }
-
-  GmsVersionCohort gms_version_cohort =
-      password_manager_android_util::GetGmsVersionCohort();
-  if (gms_version_cohort == GmsVersionCohort::kFullUpmSupport &&
-      !password_manager_android_util::LastMigrationAttemptToUpmLocalFailed()) {
-    // There is already full UPM support. No need to show any warning.
-    return;
-  }
-
-  if (GetPrefs()
-          ->FindPreference(
-              password_manager::prefs::kEmptyProfileStoreLoginDatabase)
-          ->IsDefaultValue()) {
-    // The state of the login db is unknown. This pref is initialized on
-    // startup, so it should be available in the next session at the latest.
-    return;
-  }
-
-  if (!GetPrefs()->GetBoolean(
-          password_manager::prefs::kEmptyProfileStoreLoginDatabase)) {
-    // This is to run the function after all the initialization tasks have been
-    // completed.
-    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE, base::BindOnce(&ShowAccessLossWarning, GetPrefs(),
-                                  web_contents()->GetWeakPtr(), profile_));
-    return;
-  }
-
-  // Unless a user has account UPM support, no passwords in the login DB means
-  // they're not a password manager user, so they shouldn't see the warning.
-  if (gms_version_cohort != GmsVersionCohort::kOnlyAccountUpmSupport) {
-    return;
-  }
-
-  // If the user has only account UPM support, they might still have passwords
-  // in GMS core. The support for this state will be removed in the future, so
-  // they also need to see the warning.
-  const syncer::SyncService* sync_service =
-      SyncServiceFactory::GetForProfile(profile_);
-  // If the user hasn't chosen to sync passwords, they don't store passwords in
-  // this version of GMS Core.
-  if (!sync_service ||
-      !password_manager::sync_util::HasChosenToSyncPasswords(sync_service)) {
-    return;
-  }
-
-  // The user is syncing, the login DB is empty and the GMS Core version only
-  // supports account passwords. An empty login DB combined with the other two
-  // conditions implies that the user has access to the GMS core storage,
-  // because either all their passwords were migrated and then removed or they
-  // never had any passwords in the first place, so they never needed migration.
-  password_manager::PasswordStoreInterface* profile_password_store =
-      GetProfilePasswordStore();
-  password_access_loss_warning_startup_launcher_ =
-      std::make_unique<PasswordAccessLossWarningStartupLauncher>(
-          base::BindOnce(&ShowAccessLossWarning, GetPrefs(),
-                         web_contents()->GetWeakPtr(), profile_));
-  password_access_loss_warning_startup_launcher_->FetchPasswordsAndShowWarning(
-      profile_password_store);
-}
 #endif
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(ChromePasswordManagerClient);
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index c75fb83..759d18dd 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -52,7 +52,6 @@
 #include "chrome/browser/password_manager/android/cct_password_saving_metrics_recorder_bridge.h"
 #include "chrome/browser/password_manager/android/cred_man_controller.h"
 #include "chrome/browser/password_manager/android/generated_password_saved_message_delegate.h"
-#include "chrome/browser/password_manager/android/password_access_loss_warning_startup_launcher.h"
 #include "chrome/browser/password_manager/android/password_manager_error_message_delegate.h"
 #include "chrome/browser/password_manager/android/save_update_password_message_delegate.h"
 #include "chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller.h"
@@ -492,9 +491,6 @@
   // needed.
   void TryToShowPostPasswordMigrationSheet();
 
-  // Called on startup. It will show the access loss warning sheet if needed.
-  void TryToShowAccessLossWarningSheet();
-
   password_manager::CredManController* GetOrCreateCredManController();
 
   base::WeakPtr<password_manager::KeyboardReplacingSurfaceVisibilityController>
@@ -591,11 +587,6 @@
   std::optional<std::pair<std::u16string, base::Time>>
       username_filled_by_touch_to_fill_ = std::nullopt;
 
-  // Launcher used to trigger the password access loss warning once passwords
-  // have been fetched. Only invoked once on startup.
-  std::unique_ptr<PasswordAccessLossWarningStartupLauncher>
-      password_access_loss_warning_startup_launcher_;
-
   // Recorder of metrics that is associated with the first page loaded by a
   // CCT. Created only if the WebContents corresponds to a CCT. Records
   // metrics on destruction, which happens on navigation.
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 70fa106..1723d23 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -352,7 +352,6 @@
             password_client,
             driver_supplier,
             /*grouped_credential_sheet_controller=*/nullptr,
-            /*access_loss_warning_bridge=*/nullptr,
             /*password_manager_error_message_helper_bridge=*/nullptr) {}
 
   MOCK_METHOD(void,
diff --git a/chrome/browser/password_manager/factories/password_store_backend_factory.cc b/chrome/browser/password_manager/factories/password_store_backend_factory.cc
index 4cfd2f3..1080857 100644
--- a/chrome/browser/password_manager/factories/password_store_backend_factory.cc
+++ b/chrome/browser/password_manager/factories/password_store_backend_factory.cc
@@ -13,7 +13,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/password_manager/android/password_manager_util_bridge.h"
 #include "chrome/browser/password_manager/android/password_store_empty_backend.h"
-#include "chrome/browser/password_manager/android/password_store_proxy_backend.h"
 #include "components/password_manager/core/browser/affiliation/password_affiliation_source_adapter.h"
 #include "components/password_manager/core/browser/features/password_features.h"
 #include "components/password_manager/core/browser/password_manager_buildflags.h"
@@ -30,8 +29,6 @@
 #include "chrome/browser/password_manager/android/password_manager_eviction_util.h"
 #include "chrome/browser/password_manager/android/password_store_android_account_backend.h"
 #include "chrome/browser/password_manager/android/password_store_android_local_backend.h"
-#include "chrome/browser/password_manager/android/password_store_backend_migration_decorator.h"
-#include "chrome/browser/password_manager/android/password_store_proxy_backend.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #endif  // !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
 
@@ -136,57 +133,6 @@
   return std::make_unique<password_manager::PasswordStoreEmptyBackend>();
 }
 
-// TODO(crbug.com/378653024): Remove this function after login db deprecation.
-std::unique_ptr<PasswordStoreBackend>
-CreateProfilePasswordStoreBackendForUpmAndroid(
-    PrefService* prefs,
-    const base::FilePath& login_db_directory,
-    os_crypt_async::OSCryptAsync* os_crypt_async) {
-  base::UmaHistogramBoolean(
-      "PasswordManager.PasswordStore.WasEnrolledInUPMWhenBackendWasCreated",
-      !prefs->GetBoolean(password_manager::prefs::
-                             kUnenrolledFromGoogleMobileServicesDueToErrors));
-  auto useSplitStores =
-      static_cast<UseUpmLocalAndSeparateStoresState>(prefs->GetInteger(
-          password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores));
-  // Creates the password store backend for the profile store on Android
-  // platform when UPM is enabled. There are 3 cases:
-  switch (useSplitStores) {
-    // UPM M3: The password store migration decorator is created as backend. It
-    // is expected to migrate the passwords from the built in profile store to
-    // the GMS core local store.
-    case UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending:
-      return std::make_unique<
-          password_manager::PasswordStoreBackendMigrationDecorator>(
-          CreateProfilePasswordStoreBuiltInBackend(login_db_directory, prefs,
-                                                   os_crypt_async),
-          std::make_unique<password_manager::PasswordStoreAndroidLocalBackend>(
-              prefs),
-          prefs);
-    // UPM M2: The password store proxy backend is created. No migrations are
-    // needed.
-    case UseUpmLocalAndSeparateStoresState::kOn:
-      return std::make_unique<
-          password_manager::PasswordStoreAndroidLocalBackend>(prefs);
-    // Old UPM: support for local passwords in GMSCore is unavailable for some
-    // reason.
-    case UseUpmLocalAndSeparateStoresState::kOff: {
-      // Even though this is a backend for a ProfilePasswordStore it has to
-      // talk to the account. Before the store split, the `ProfilePasswordStore`
-      // only supports talking to the account storage in GMS Core. All local
-      // storage requests go to the built-in backend instead.
-      auto android_account_backend = std::make_unique<
-          password_manager::PasswordStoreAndroidAccountBackend>(
-          prefs, password_manager::kProfileStore);
-      // Chrome stopped trying to migrate passwords to the account GMSCore
-      // storage. Only PasswordStoreProxyBackend is created.
-      return std::make_unique<password_manager::PasswordStoreProxyBackend>(
-          CreateProfilePasswordStoreBuiltInBackend(login_db_directory, prefs,
-                                                   os_crypt_async),
-          std::move(android_account_backend), prefs);
-    }
-  }
-}
 #endif  // !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
 }  // namespace
 
@@ -197,25 +143,16 @@
   TRACE_EVENT0("passwords", "PasswordStoreBackendCreation");
 
 #if !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid)) {
-    // During the login DB deprecation, only the built-in backend should be
-    // instantiated. After the unmigrated passwords are exported, the login DB
-    // is considered deprecated. There will be only 2 options for
-    // the backend: an empty one if the Android backend isn't supported,
-    // or the Android backend.
-    return CreateProfilePasswordStoreBackendAndroid(prefs, login_db_directory,
-                                                    os_crypt_async);
-  }
-
-  // This are the absolute minimum requirements to have any version of UPM.
-  if (password_manager_android_util::AreMinUpmRequirementsMet()) {
-    return CreateProfilePasswordStoreBackendForUpmAndroid(
-        prefs, login_db_directory, os_crypt_async);
-  }
-#endif  // !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
+  // Only the built-in backend should be instantiated. After the unmigrated
+  // passwords are exported, the login DB is considered deprecated. There will
+  // be only 2 options for the backend: an empty one if the Android backend
+  // isn't supported, or the Android backend.
+  return CreateProfilePasswordStoreBackendAndroid(prefs, login_db_directory,
+                                                  os_crypt_async);
+#else
   return CreateProfilePasswordStoreBuiltInBackend(login_db_directory, prefs,
                                                   os_crypt_async);
+#endif
 }
 
 std::unique_ptr<PasswordStoreBackend> CreateAccountPasswordStoreBackend(
diff --git a/chrome/browser/password_manager/password_manager_settings_service_factory.cc b/chrome/browser/password_manager/password_manager_settings_service_factory.cc
index 66501d4..aa47f80 100644
--- a/chrome/browser/password_manager/password_manager_settings_service_factory.cc
+++ b/chrome/browser/password_manager/password_manager_settings_service_factory.cc
@@ -16,7 +16,6 @@
 #if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/password_manager_settings_service_android_impl.h"
-#include "chrome/browser/password_manager/android/password_manager_settings_service_android_migration_impl.h"
 #include "chrome/browser/password_manager/android/password_manager_util_bridge.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -85,25 +84,19 @@
 std::unique_ptr<password_manager::PasswordManagerSettingsService>
 PasswordManagerSettingsServiceFactory::CreateService(Profile* profile) const {
 #if BUILDFLAG(IS_ANDROID)
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kLoginDbDeprecationAndroid)) {
-    // For the first run after the feature is enabled, before the unmigrated
-    // passwords are exported, `IsPasswordManagerAvailable` can return false.
-    // However, password saving isn't possible in that run anyway.
-    if (password_manager_android_util::IsPasswordManagerAvailable(
-            profile->GetPrefs(),
-            std::make_unique<
-                password_manager_android_util::PasswordManagerUtilBridge>())) {
-      return std::make_unique<PasswordManagerSettingsServiceAndroidImpl>(
-          profile->GetPrefs(), SyncServiceFactory::GetForProfile(profile));
-    }
-    return nullptr;
-  }
-  if (password_manager_android_util::AreMinUpmRequirementsMet()) {
-    return std::make_unique<PasswordManagerSettingsServiceAndroidMigrationImpl>(
+  // For the first run after the feature is enabled, before the unmigrated
+  // passwords are exported, `IsPasswordManagerAvailable` can return false.
+  // However, password saving isn't possible in that run anyway.
+  if (password_manager_android_util::IsPasswordManagerAvailable(
+          profile->GetPrefs(),
+          std::make_unique<
+              password_manager_android_util::PasswordManagerUtilBridge>())) {
+    return std::make_unique<PasswordManagerSettingsServiceAndroidImpl>(
         profile->GetPrefs(), SyncServiceFactory::GetForProfile(profile));
   }
-#endif
+  return nullptr;
+#else
   return std::make_unique<password_manager::PasswordManagerSettingsServiceImpl>(
       profile->GetPrefs());
+#endif
 }
diff --git a/chrome/browser/password_manager/password_manager_test_util.cc b/chrome/browser/password_manager/password_manager_test_util.cc
index 59a1975..13c7d8f73 100644
--- a/chrome/browser/password_manager/password_manager_test_util.cc
+++ b/chrome/browser/password_manager/password_manager_test_util.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/password_manager/profile_password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/password_manager/core/browser/features/password_features.h"
-#include "components/password_manager/core/browser/features/password_manager_features_util.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/password_store/test_password_store.h"
 
@@ -28,10 +27,6 @@
 
 scoped_refptr<TestPasswordStore> CreateAndUseTestAccountPasswordStore(
     content::BrowserContext* context) {
-  if (!password_manager::features_util::CanCreateAccountStore(
-          Profile::FromBrowserContext(context)->GetPrefs())) {
-    return nullptr;
-  }
   TestPasswordStore* store = static_cast<TestPasswordStore*>(
       AccountPasswordStoreFactory::GetInstance()
           ->SetTestingFactoryAndUse(
diff --git a/chrome/browser/password_manager/password_receiver_service_factory.cc b/chrome/browser/password_manager/password_receiver_service_factory.cc
index 2c8e43dc..cbc2263 100644
--- a/chrome/browser/password_manager/password_receiver_service_factory.cc
+++ b/chrome/browser/password_manager/password_receiver_service_factory.cc
@@ -77,7 +77,7 @@
       DataTypeStoreServiceFactory::GetForProfile(profile)->GetStoreFactory());
 
   return std::make_unique<password_manager::PasswordReceiverServiceImpl>(
-      profile->GetPrefs(), std::move(sync_bridge),
+      std::move(sync_bridge),
       ProfilePasswordStoreFactory::GetForProfile(
           profile, ServiceAccessType::EXPLICIT_ACCESS)
           .get(),
diff --git a/chrome/browser/picture_in_picture/document_picture_in_picture_pixel_browsertest.cc b/chrome/browser/picture_in_picture/document_picture_in_picture_pixel_browsertest.cc
index 1c6118e2..a71369b 100644
--- a/chrome/browser/picture_in_picture/document_picture_in_picture_pixel_browsertest.cc
+++ b/chrome/browser/picture_in_picture/document_picture_in_picture_pixel_browsertest.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/document_picture_in_picture_window_controller.h"
 
 #include "base/strings/string_number_conversions.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/test/test_browser_ui.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view.h"
@@ -152,6 +153,10 @@
   }
 
  private:
+ // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   raw_ptr<content::DocumentPictureInPictureWindowController>
       pip_window_controller_ = nullptr;
   base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/chrome/browser/picture_in_picture/test/android/java/src/org/chromium/chrome/browser/picture_in_picture/AutoPiPTabModelObserverHelperTest.java b/chrome/browser/picture_in_picture/test/android/java/src/org/chromium/chrome/browser/picture_in_picture/AutoPiPTabModelObserverHelperTest.java
index daf29c0..a929c10 100644
--- a/chrome/browser/picture_in_picture/test/android/java/src/org/chromium/chrome/browser/picture_in_picture/AutoPiPTabModelObserverHelperTest.java
+++ b/chrome/browser/picture_in_picture/test/android/java/src/org/chromium/chrome/browser/picture_in_picture/AutoPiPTabModelObserverHelperTest.java
@@ -42,7 +42,7 @@
 import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule;
 import org.chromium.chrome.test.transit.ChromeTransitTestRules;
 import org.chromium.chrome.test.transit.hub.RegularTabSwitcherStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.MenuUtils;
@@ -127,7 +127,7 @@
     public void testTriggersOnTabActivationChanged() throws TimeoutException {
         int callCount = startObservingAndAssertInitialCallback(/* expectedIsActivated= */ true);
 
-        PageStation page = mInitialPage.openNewTabFast();
+        CtaPageStation page = mInitialPage.openNewTabFast();
         mOnActivationChangedCallbackHelper.waitForCallback(callCount++);
         assertFalse(mOnActivationChangedCallbackHelper.isActivated());
 
@@ -143,7 +143,7 @@
         int callCount = startObservingAndAssertInitialCallback(/* expectedIsActivated= */ true);
 
         AutoPiPTabModelObserverHelperTestUtils.stopObserving();
-        PageStation page = mInitialPage.openNewTabFast();
+        CtaPageStation page = mInitialPage.openNewTabFast();
         assertEquals(
                 "Callback should not have fired after stopping observation.",
                 callCount,
@@ -201,7 +201,7 @@
         int callCount = startObservingAndAssertInitialCallback(/* expectedIsActivated= */ true);
 
         // Open a second tab and switch to it
-        PageStation page = mInitialPage.openNewTabFast();
+        CtaPageStation page = mInitialPage.openNewTabFast();
         mOnActivationChangedCallbackHelper.waitForCallback(callCount++);
         assertFalse(mOnActivationChangedCallbackHelper.isActivated());
 
@@ -255,7 +255,7 @@
         }
         int callCount = startObservingAndAssertInitialCallback(/* expectedIsActivated= */ true);
         // Open a new tab
-        PageStation page = mInitialPage.openNewTabFast();
+        CtaPageStation page = mInitialPage.openNewTabFast();
         mOnActivationChangedCallbackHelper.waitForCallback(callCount++);
         assertFalse(mOnActivationChangedCallbackHelper.isActivated());
         // Switch back to the original tab
diff --git a/chrome/browser/platform_experience/win b/chrome/browser/platform_experience/win
index 47650f3..e913d61 160000
--- a/chrome/browser/platform_experience/win
+++ b/chrome/browser/platform_experience/win
@@ -1 +1 @@
-Subproject commit 47650f3a9a6f66c92e1069dfe2db3db1c48f76d3
+Subproject commit e913d6144929b67b0123235efc020a1bb138c8ae
diff --git a/chrome/browser/policy/policy_path_parser_linux.cc b/chrome/browser/policy/policy_path_parser_linux.cc
index 25026414f..0c0fd5f 100644
--- a/chrome/browser/policy/policy_path_parser_linux.cc
+++ b/chrome/browser/policy/policy_path_parser_linux.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 <pwd.h>
 #include <stddef.h>
 #include <string.h>
diff --git a/chrome/browser/policy/test/policy_test_google_browsertest.cc b/chrome/browser/policy/test/policy_test_google_browsertest.cc
index 384259dd..e1bdbc2 100644
--- a/chrome/browser/policy/test/policy_test_google_browsertest.cc
+++ b/chrome/browser/policy/test/policy_test_google_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/test/bind.h"
 #include "base/values.h"
 #include "chrome/browser/policy/safe_search_policy_test.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -113,6 +114,10 @@
 
   bool is_incognito() const { return GetParam(); }
 
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   net::EmbeddedTestServer https_server_;
   base::Lock lock_;
   std::map<std::string, net::HttpRequestHeaders> urls_requested_;
diff --git a/chrome/browser/policy/url_blocking_policy_test_utils.h b/chrome/browser/policy/url_blocking_policy_test_utils.h
index fa8e414..ea5825c 100644
--- a/chrome/browser/policy/url_blocking_policy_test_utils.h
+++ b/chrome/browser/policy/url_blocking_policy_test_utils.h
@@ -9,6 +9,8 @@
 
 #include "chrome/browser/policy/policy_test_utils.h"
 
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
+
 class Browser;
 class GURL;
 
@@ -32,6 +34,12 @@
 
   // Verifies that access to |view-source:spec| is blocked.
   void CheckViewSourceURLIsBlocked(Browser* browser, const std::string& spec);
+
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 }  // namespace policy
diff --git a/chrome/browser/predictors/preconnect_manager_impl.cc b/chrome/browser/predictors/preconnect_manager_impl.cc
index 58d19be..2dd50c6 100644
--- a/chrome/browser/predictors/preconnect_manager_impl.cc
+++ b/chrome/browser/predictors/preconnect_manager_impl.cc
@@ -13,7 +13,6 @@
 #include "base/trace_event/trace_event.h"
 #include "base/types/optional_util.h"
 #include "chrome/browser/predictors/predictors_features.h"
-#include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 20605a27..f6ba13e 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1022,6 +1022,18 @@
 inline constexpr char kSyncedDefaultSearchProviderGUID[] =
     "default_search_provider.synced_guid";
 
+#if BUILDFLAG(IS_ANDROID)
+// Deprecated 07/2025.
+constexpr char kObsoletePasswordAccessLossWarningShownAtStartupTimestamp[] =
+    "password_access_loss_warning_shown_at_startup_timestamp";
+constexpr char kObsoletePasswordAccessLossWarningShownTimestamp[] =
+    "password_access_loss_warning_shown_timestamp";
+constexpr char kObsoleteTimeOfLastMigrationAttempt[] =
+    "time_of_last_migration_attempt";
+constexpr char kObsoleteSettingsMigratedToUPMLocal[] =
+    "profile.settings_migrated_to_upm_local";
+#endif  // BUILDFLAG(IS_ANDROID)
+
 // Deprecated 07/2025.
 inline constexpr char kFirstSyncCompletedInFullSyncMode[] =
     "sync.first_full_sync_completed";
@@ -1449,6 +1461,16 @@
   registry->RegisterStringPref(kLastUsedPairingFromSyncPublicKey, "");
   registry->RegisterStringPref(kSyncedDefaultSearchProviderGUID, std::string());
 
+#if BUILDFLAG(IS_ANDROID)
+  // Deprecated 07/2025.
+  registry->RegisterTimePref(
+      kObsoletePasswordAccessLossWarningShownAtStartupTimestamp, base::Time());
+  registry->RegisterTimePref(kObsoletePasswordAccessLossWarningShownTimestamp,
+                             base::Time());
+  registry->RegisterDoublePref(kObsoleteTimeOfLastMigrationAttempt, 0.0);
+  registry->RegisterBooleanPref(kObsoleteSettingsMigratedToUPMLocal, false);
+#endif  // BUILDFLAG(IS_ANDROID)
+
   // Deprecated 07/2025.
   registry->RegisterBooleanPref(kFirstSyncCompletedInFullSyncMode, false);
   registry->RegisterStringPref(kGoogleServicesSecondLastSyncingGaiaId,
@@ -1780,6 +1802,10 @@
 
   registry->RegisterIntegerPref(prefs::kToastAlertLevel, 0);
 
+#if !BUILDFLAG(IS_ANDROID)
+  registry->RegisterStringPref(prefs::kNonMilestoneUpdateToastVersion, "");
+#endif  // !BUILDFLAG(IS_ANDROID)
+
   // This is intentionally last.
   RegisterLocalStatePrefsForMigration(registry);
 }
@@ -2714,6 +2740,15 @@
   profile_prefs->ClearPref(kLastUsedPairingFromSyncPublicKey);
   profile_prefs->ClearPref(kSyncedDefaultSearchProviderGUID);
 
+#if BUILDFLAG(IS_ANDROID)
+  // Deprecated 07/2025.
+  profile_prefs->ClearPref(
+      kObsoletePasswordAccessLossWarningShownAtStartupTimestamp);
+  profile_prefs->ClearPref(kObsoletePasswordAccessLossWarningShownTimestamp);
+  profile_prefs->ClearPref(kObsoleteTimeOfLastMigrationAttempt);
+  profile_prefs->ClearPref(kObsoleteSettingsMigratedToUPMLocal);
+#endif  // BUILDFLAG(IS_ANDROID)
+
   // Added 07/2025.
   profile_prefs->ClearPref(kFirstSyncCompletedInFullSyncMode);
   profile_prefs->ClearPref(kGoogleServicesSecondLastSyncingGaiaId);
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc b/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc
index 3d35a873..146bdd6 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store_proxy_unittest.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store_proxy_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <gtest/gtest.h>
 #include <stddef.h>
 
 #include "base/command_line.h"
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/prefs/chrome_command_line_pref_store.h"
 #include "chrome/common/chrome_switches.h"
@@ -166,8 +162,8 @@
 
   void SetUp() override {
     for (size_t i = 0; i < std::size(GetParam().switches); i++) {
-      const char* name = GetParam().switches[i].name;
-      const char* value = GetParam().switches[i].value;
+      const char* name = UNSAFE_TODO(GetParam().switches[i]).name;
+      const char* value = UNSAFE_TODO(GetParam().switches[i]).value;
       if (name && value)
         command_line_.AppendSwitchASCII(name, value);
       else if (name)
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store_unittest.cc b/chrome/browser/prefs/chrome_command_line_pref_store_unittest.cc
index 251a1fa9..b7f7d14 100644
--- a/chrome/browser/prefs/chrome_command_line_pref_store_unittest.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/prefs/chrome_command_line_pref_store.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 #include <array>
 
 #include "base/command_line.h"
+#include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/strings/string_util.h"
@@ -63,7 +59,7 @@
 
     for (const base::Value& cipher_string : value->GetList()) {
       ASSERT_TRUE(cipher_string.is_string());
-      EXPECT_EQ(*ciphers++, cipher_string.GetString());
+      UNSAFE_TODO(EXPECT_EQ(*ciphers++, cipher_string.GetString()));
     }
   }
 
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
index d70af05..fb59dad 100644
--- a/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
+++ b/chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h"
 #include "chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h"
 #include "chrome/browser/preloading/preloading_prefs.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -484,6 +485,10 @@
   }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::ScopedMockElapsedTimersForTest scoped_test_timer_;
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
diff --git a/chrome/browser/printing/pdf_nup_converter_client_browsertest.cc b/chrome/browser/printing/pdf_nup_converter_client_browsertest.cc
index 021e7a9..a1761113 100644
--- a/chrome/browser/printing/pdf_nup_converter_client_browsertest.cc
+++ b/chrome/browser/printing/pdf_nup_converter_client_browsertest.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 "chrome/browser/printing/pdf_nup_converter_client.h"
 
 #include <optional>
@@ -15,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
@@ -60,7 +56,8 @@
   if (!pdf_region.IsValid())
     return pdf_region;
 
-  memcpy(pdf_region.mapping.memory(), pdf_str.data(), pdf_str.size());
+  UNSAFE_TODO(
+      memcpy(pdf_region.mapping.memory(), pdf_str.data(), pdf_str.size()));
   return pdf_region;
 }
 
@@ -71,7 +68,8 @@
   if (!pdf_region.IsValid())
     return pdf_region;
 
-  memcpy(pdf_region.mapping.memory(), kBadData, std::size(kBadData));
+  UNSAFE_TODO(
+      memcpy(pdf_region.mapping.memory(), kBadData, std::size(kBadData)));
   return pdf_region;
 }
 
diff --git a/chrome/browser/private_network_access/local_network_access_browsertest.cc b/chrome/browser/private_network_access/local_network_access_browsertest.cc
index 3f88213..00cdf41 100644
--- a/chrome/browser/private_network_access/local_network_access_browsertest.cc
+++ b/chrome/browser/private_network_access/local_network_access_browsertest.cc
@@ -102,8 +102,7 @@
   base::HistogramTester histogram_;
 };
 
-IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest,
-                       CheckSecurityStateDefaultPolicyDenyPermission) {
+IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, FetchDenyPermission) {
   ASSERT_TRUE(content::NavigateToURL(
       web_contents(),
       https_server().GetURL(
@@ -127,8 +126,7 @@
               content::EvalJsResult::IsError());
 }
 
-IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest,
-                       CheckSecurityStateDefaultPolicyAcceptPermission) {
+IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, FetchAcceptPermission) {
   ASSERT_TRUE(content::NavigateToURL(
       web_contents(),
       https_server().GetURL(
@@ -152,6 +150,70 @@
                                    https_server().GetURL("b.com", kLnaPath))));
 }
 
+IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, IframeDenyPermission) {
+  ASSERT_TRUE(content::NavigateToURL(
+      web_contents(),
+      https_server().GetURL(
+          "a.com",
+          "/private_network_access/no-favicon-treat-as-public-address.html")));
+
+  permissions::PermissionRequestManager* manager =
+      permissions::PermissionRequestManager::FromWebContents(web_contents());
+  std::unique_ptr<permissions::MockPermissionPromptFactory> bubble_factory =
+      std::make_unique<permissions::MockPermissionPromptFactory>(manager);
+
+  // Enable auto-denial of LNA permission request.
+  bubble_factory->set_response_type(
+      permissions::PermissionRequestManager::AutoResponseType::DENY_ALL);
+
+  GURL iframe_url = https_server().GetURL("b.com", kLnaPath);
+  content::TestNavigationManager nav_manager(web_contents(), iframe_url);
+  std::string_view script_template = R"(
+    const child = document.createElement("iframe");
+    child.src = $1;
+    document.body.appendChild(child);
+  )";
+  EXPECT_THAT(content::EvalJs(web_contents(),
+                              content::JsReplace(script_template, iframe_url)),
+              content::EvalJsResult::IsOk());
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
+
+  // Check that the child iframe failed to fetch.
+  EXPECT_FALSE(nav_manager.was_successful());
+}
+
+IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, IframeAcceptPermission) {
+  ASSERT_TRUE(content::NavigateToURL(
+      web_contents(),
+      https_server().GetURL(
+          "a.com",
+          "/private_network_access/no-favicon-treat-as-public-address.html")));
+
+  permissions::PermissionRequestManager* manager =
+      permissions::PermissionRequestManager::FromWebContents(web_contents());
+  std::unique_ptr<permissions::MockPermissionPromptFactory> bubble_factory =
+      std::make_unique<permissions::MockPermissionPromptFactory>(manager);
+
+  // Enable auto-accept of LNA permission request.
+  bubble_factory->set_response_type(
+      permissions::PermissionRequestManager::AutoResponseType::ACCEPT_ALL);
+
+  GURL iframe_url = https_server().GetURL("b.com", kLnaPath);
+  content::TestNavigationManager nav_manager(web_contents(), iframe_url);
+  std::string_view script_template = R"(
+    const child = document.createElement("iframe");
+    child.src = $1;
+    document.body.appendChild(child);
+  )";
+  EXPECT_THAT(content::EvalJs(web_contents(),
+                              content::JsReplace(script_template, iframe_url)),
+              content::EvalJsResult::IsOk());
+  ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
+
+  // Check that the child iframe failed to fetch.
+  EXPECT_TRUE(nav_manager.was_successful());
+}
+
 IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest,
                        CheckSecurityStatePolicySet) {
   policy::PolicyMap policies;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background.ts
index 53113aa..e60e8c3 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/background/background.ts
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Required so that learn mode tests can use LearnModeBridge.
 import '../common/learn_mode_bridge.js';
 
+import {BridgeHelper} from '/common/bridge_helper.js';
 import {Features} from '/common/features.js';
 import {Flags} from '/common/flags.js';
 import {KeepAlive} from '/common/keep_alive.js';
@@ -12,6 +14,7 @@
 
 import type {BrailleKeyEvent} from '../common/braille/braille_key_types.js';
 import {NavBraille} from '../common/braille/nav_braille.js';
+import {BridgeConstants} from '../common/bridge_constants.js';
 import {EarconId} from '../common/earcon_id.js';
 import {LocaleOutputHelper} from '../common/locale_output_helper.js';
 import {Msgs} from '../common/msgs.js';
@@ -90,6 +93,12 @@
     chrome.accessibilityPrivate.onShowChromeVoxTutorial.addListener(() => {
       (new PanelCommand(PanelCommandType.TUTORIAL)).send();
     });
+
+    BridgeHelper.registerHandler(
+        BridgeConstants.ChromeVoxState.TARGET,
+        BridgeConstants.ChromeVoxState.Action.IS_LEARN_MODE_READY, () => {
+          return this.isLearnModeReady_();
+        });
   }
 
   static async init(): Promise<void> {
@@ -209,6 +218,18 @@
         }));
     ChromeVox.braille.write(NavBraille.fromText(Msgs.getMsg('intro_brl')));
   }
+
+  // Returns true if the learn mode page is open and ready to receive messages
+  // and returns false otherwise.
+  private async isLearnModeReady_(): Promise<boolean> {
+    const learnModeUrl =
+        chrome.runtime.getURL('chromevox/mv3/learn_mode/learn_mode.html');
+    const existingContexts = await chrome.runtime.getContexts({
+      documentUrls: [learnModeUrl],
+    });
+
+    return existingContexts.length > 0;
+  }
 }
 
 InstanceChecker.closeExtraInstances();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts
index 103f88c6..a95dddc 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/bridge_constants.ts
@@ -65,6 +65,13 @@
     },
   },
 
+  ChromeVoxState: {
+    TARGET: 'ChromeVoxState',
+    Action: {
+      IS_LEARN_MODE_READY: 'isLearnModeReady',
+    },
+  },
+
   CommandHandler: {
     TARGET: 'CommandHandler',
     Action: {
@@ -125,7 +132,6 @@
       CLEAR_TOUCH_EXPLORE_OUTPUT_TIME: 'clearTouchExploreOutputTime',
       ON_ACCESSIBILITY_GESTURE: 'onAccessibilityGesture',
       ON_BRAILLE_KEY_EVENT: 'onBrailleKeyEvent',
-      READY: 'ready',
     },
   },
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/learn_mode_bridge.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/learn_mode_bridge.ts
index a582aa67..44c0ba6 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/learn_mode_bridge.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/common/learn_mode_bridge.ts
@@ -20,41 +20,88 @@
 const LearnModeTestAction = BridgeConstants.LearnModeTest.Action;
 
 export class LearnModeBridge {
-  static onKeyDown(internalEvent: InternalKeyEvent): Promise<boolean> {
+  // We need to call this method before sending a message to the learn mode
+  // page, otherwise, we will encounter errors like "Unchecked
+  // runtime.lastError: The message port closed before a response was received".
+  private static async isLearnModeReady_(): Promise<boolean> {
+    if (chrome.runtime && chrome.runtime.getContexts) {
+      // If the calling context has access to the necessary API, then use it
+      // directly.
+      const learnModeUrl =
+          chrome.runtime.getURL('chromevox/mv3/learn_mode/learn_mode.html');
+      const existingContexts = await chrome.runtime.getContexts({
+        documentUrls: [learnModeUrl],
+      });
+
+      return existingContexts.length > 0;
+    }
+
+    // Otherwise, ask the service worker if learn mode is ready.
+    return BridgeHelper.sendMessage(
+        BridgeConstants.ChromeVoxState.TARGET,
+        BridgeConstants.ChromeVoxState.Action.IS_LEARN_MODE_READY);
+  }
+
+  static async onKeyDown(internalEvent: InternalKeyEvent): Promise<boolean> {
+    const ready = await LearnModeBridge.isLearnModeReady_();
+    if (!ready) {
+      return false;
+    }
+
     return BridgeHelper.sendMessage(
         LearnModeTarget, LearnModeAction.ON_KEY_DOWN, internalEvent);
   }
 
-  static onKeyUp(): Promise<void> {
+  static async onKeyUp(): Promise<void> {
+    const ready = await LearnModeBridge.isLearnModeReady_();
+    if (!ready) {
+      return;
+    }
+
     return BridgeHelper.sendMessage(LearnModeTarget, LearnModeAction.ON_KEY_UP);
   }
 
-  static onKeyPress(): Promise<void> {
+  static async onKeyPress(): Promise<void> {
+    const ready = await LearnModeBridge.isLearnModeReady_();
+    if (!ready) {
+      return;
+    }
+
     return BridgeHelper.sendMessage(
         LearnModeTarget, LearnModeAction.ON_KEY_PRESS);
   }
 
-  static clearTouchExploreOutputTimeForTest(): Promise<void> {
+  static async clearTouchExploreOutputTimeForTest(): Promise<void> {
+    const ready = await LearnModeBridge.isLearnModeReady_();
+    if (!ready) {
+      return;
+    }
+
     return BridgeHelper.sendMessage(
         LearnModeTestTarget,
         LearnModeTestAction.CLEAR_TOUCH_EXPLORE_OUTPUT_TIME);
   }
 
-  static onAccessibilityGestureForTest(gesture: string): Promise<void> {
+  static async onAccessibilityGestureForTest(gesture: string): Promise<void> {
+    const ready = await LearnModeBridge.isLearnModeReady_();
+    if (!ready) {
+      return;
+    }
+
     return BridgeHelper.sendMessage(
         LearnModeTestTarget, LearnModeTestAction.ON_ACCESSIBILITY_GESTURE,
         gesture);
   }
 
-  static onBrailleKeyEventForTest(event: BrailleKeyEvent): Promise<void> {
+  static async onBrailleKeyEventForTest(event: BrailleKeyEvent): Promise<void> {
+    const ready = await LearnModeBridge.isLearnModeReady_();
+    if (!ready) {
+      return;
+    }
+
     return BridgeHelper.sendMessage(
         LearnModeTestTarget, LearnModeTestAction.ON_BRAILLE_KEY_EVENT, event);
   }
-
-  static readyForTest(): Promise<void> {
-    return BridgeHelper.sendMessage(
-        LearnModeTestTarget, LearnModeTestAction.READY);
-  }
 }
 
 TestImportManager.exportForTesting(LearnModeBridge);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts
index 7d09448d..1e3b9187 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode.ts
@@ -87,10 +87,6 @@
         TestTARGET, TestAction.ON_BRAILLE_KEY_EVENT,
         (event: chrome.brailleDisplayPrivate.KeyEvent) =>
             LearnMode.onBrailleKeyEvent(event));
-    BridgeHelper.registerHandler(
-        TestTARGET, TestAction.READY, () => readyPromise);
-
-    readyCallback();
   }
 
   /**
@@ -368,8 +364,3 @@
  * The minimum time to wait before describing another touch explore gesture.
  */
 let MIN_TOUCH_EXPLORE_OUTPUT_TIME_MS = 1000;
-
-
-let readyCallback: VoidFunction;
-const readyPromise =
-    new Promise(resolve => readyCallback = resolve as VoidFunction);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode_test.js
index c80f3ff..cfa4c302 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/learn_mode/learn_mode_test.js
@@ -22,6 +22,13 @@
     globalThis.doBrailleKeyEvent = this.doBrailleKeyEvent.bind(this);
   }
 
+  /** @override */
+  async setUpDeferred() {
+    await super.setUpDeferred();
+    const imports = TestImportManager.getImports();
+    globalThis.LearnModeBridge = imports.LearnModeBridge;
+  }
+
   async runOnLearnModePage() {
     return new Promise(async resolve => {
       const mockFeedback = this.createMockFeedback();
@@ -187,7 +194,6 @@
 AX_TEST_F(
     'ChromeVoxLearnModeTest', 'CommandHandlersDisabled', async function() {
       const [mockFeedback, evt] = await this.runOnLearnModePage();
-      await LearnModeBridge.readyForTest();
       assertTrue(BrailleCommandHandler.instance.bypassed_);
       assertTrue(GestureCommandHandler.instance.bypassed_);
       await mockFeedback.replay();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts
index 96d41e9..4934d6c9 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/offscreen/offscreen.ts
@@ -31,8 +31,9 @@
 
   static init(): void {
     if (OffscreenChromeVoxState.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'OffscreenChromeVoxState.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'OffscreenChromeVoxState.');
     }
     OffscreenChromeVoxState.instance = new OffscreenChromeVoxState();
   }
@@ -57,8 +58,9 @@
 
   static init(): void {
     if (OffscreenBackgroundKeyboardHandler.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'BackgroundKeyboardHandler.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'BackgroundKeyboardHandler.');
     }
     OffscreenBackgroundKeyboardHandler.instance =
         new OffscreenBackgroundKeyboardHandler();
@@ -110,8 +112,9 @@
 
   static init(): void {
     if (OffscreenLearnModeKeyboardHandler.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'OffscreenLearnModeKeyboardHandler.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'OffscreenLearnModeKeyboardHandler.');
     }
     OffscreenLearnModeKeyboardHandler.instance =
         new OffscreenLearnModeKeyboardHandler();
@@ -174,8 +177,9 @@
 
   static init(): void {
     if (OffscreenClipboardHandler.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'OffscreenClipboardHandler.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'OffscreenClipboardHandler.');
     }
     OffscreenClipboardHandler.instance = new OffscreenClipboardHandler();
   }
@@ -240,8 +244,9 @@
 
   static init(): void {
     if (OffscreenSpeechSynthesis.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'OffscreenSpeechSynthesis.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'OffscreenSpeechSynthesis.');
     }
     OffscreenSpeechSynthesis.instance = new OffscreenSpeechSynthesis();
   }
@@ -268,8 +273,9 @@
 
   static init(): void {
     if (OffscreenBrailleDisplayManager.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'OffscreenBrailleDisplayManager.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'OffscreenBrailleDisplayManager.');
     }
     OffscreenBrailleDisplayManager.instance =
         new OffscreenBrailleDisplayManager();
@@ -315,8 +321,9 @@
 
   static init(): void {
     if (OffscreenMathHandler.instance) {
-      throw 'Error: trying to create two instances of singleton ' +
-          'OffscreenMathHandler.';
+      throw new Error(
+          'Error: trying to create two instances of singleton ' +
+          'OffscreenMathHandler.');
     }
     OffscreenMathHandler.instance = new OffscreenMathHandler();
   }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/tutorial_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/tutorial_test.js
index 0844c598..387a708 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/tutorial_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/mv3/panel/tutorial_test.js
@@ -90,10 +90,10 @@
   /** Waits for the tutorial to load. */
   async waitForTutorial_() {
     return new Promise(resolve => {
-      const intervalId = setTimeout(async () => {
+      const intervalId = setInterval(async () => {
         const ready = await PanelBridge.getTutorialReadyForTest();
         if (ready) {
-          clearTimeout(intervalId);
+          clearInterval(intervalId);
           resolve();
         }
       }, 500);
diff --git a/chrome/browser/resources/glic/glic_api/glic_api.ts b/chrome/browser/resources/glic/glic_api/glic_api.ts
index 8be1c931..7caa897 100644
--- a/chrome/browser/resources/glic/glic_api/glic_api.ts
+++ b/chrome/browser/resources/glic/glic_api/glic_api.ts
@@ -181,6 +181,12 @@
       (tabId: string, options: TabContextOptions): Promise<TabContextResult>;
 
   /**
+   * Similar to `getContextFromTab`, but for actors. Skips the focus check.
+   */
+  getContextForActorFromTab?
+      (tabId: string, options: TabContextOptions): Promise<TabContextResult>;
+
+  /**
    * Sets the maximum number of supported pinned tabs. Should not be called
    * more than once. Chrome may not be able to support the given number, so
    * the applied limit is returned.
@@ -266,6 +272,15 @@
       Promise<TabContextResult>;
 
   /**
+   * Returns the observable state of the actor task with the given ID. Updates
+   * are sent whenever:
+   * - The task is created, paused, resumed or stopped.
+   * - The task is performing an action.
+   * - The task is going away.
+   */
+  getActorTaskState?(taskId: number): ObservableValue<ActorTaskState>;
+
+  /**
    * Requests the host to capture a screenshot. The choice of the screenshot
    * target is made by the host, possibly allowing the user to choose between a
    * desktop, window or arbitrary region.
@@ -1201,6 +1216,19 @@
   TASK_SYSTEM_UNAVAILABLE = 1,
 }
 
+/** The state of the actor task. */
+export enum ActorTaskState {
+  UNKNOWN = 0,
+  /** The actor task is idle and waiting for the next action instruction. */
+  IDLE = 1,
+  /** The actor task is performing an action. */
+  ACTING = 2,
+  /** The actor task is paused and waiting to be resumed or stopped. */
+  PAUSED = 3,
+  /** The actor task is stopped and going away. */
+  STOPPED = 4,
+}
+
 export enum PerformActionsErrorReason {
   UNKNOWN = 0,
 
@@ -1600,4 +1628,5 @@
   performActionsErrorReason: typeof PerformActionsErrorReason;
   settingsPageField: typeof SettingsPageField;
   hostCapability: typeof HostCapability;
+  actorTaskState: typeof ActorTaskState;
 }
diff --git a/chrome/browser/resources/glic/glic_api_impl/conversions.ts b/chrome/browser/resources/glic/glic_api_impl/conversions.ts
index 6f79dd9..d3befa0 100644
--- a/chrome/browser/resources/glic/glic_api_impl/conversions.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/conversions.ts
@@ -90,3 +90,5 @@
     typeof api.SettingsPageField>>();
 assertNever<CheckEnumCompatibility<
     typeof mojom.HostCapability, typeof api.HostCapability>>();
+assertNever<CheckEnumCompatibility<
+    typeof mojom.ActorTaskState, typeof api.ActorTaskState>>();
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts
index baa1703..6d8ec76 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import type {ActInFocusedTabParams, ActInFocusedTabResult, AnnotatedPageData, ChromeVersion, CreateTabOptions, DraggableArea, FocusedTabData, GetPinCandidatesOptions, GlicBrowserHost, GlicBrowserHostJournal, GlicBrowserHostMetrics, GlicHostRegistry, GlicWebClient, HostCapability, Journal, ObservableValue, OpenPanelInfo, OpenSettingsOptions, PanelOpeningData, PanelState, PdfDocumentData, PinCandidate, ResizeWindowOptions, Screenshot, ScrollToParams, TabContextOptions, TabContextResult, TabData, UserProfileInfo, ZeroStateSuggestions, ZeroStateSuggestionsOptions, ZeroStateSuggestionsV2} from '../glic_api/glic_api.js';
+import {ActorTaskState} from '../glic_api/glic_api.js';
 import {ObservableValue as ObservableValueImpl} from '../observable.js';
 
 import {replaceProperties} from './conversions.js';
@@ -187,6 +188,11 @@
     });
     this.host.pinnedTabs.assignAndSignal(this.cachedPinnedTabs);
   }
+
+  glicWebClientNotifyActorTaskStateChanged(
+      payload: {taskId: number, state: ActorTaskState}): void {
+    this.host.setActorTaskState(payload.taskId, payload.state);
+  }
 }
 
 class GlicBrowserHostImpl implements GlicBrowserHost {
@@ -222,6 +228,8 @@
   currentZeroStateObserver =
       ObservableValueImpl.withNoValue<ZeroStateSuggestionsV2>();
   private hostCapabilities: Set<HostCapability> = new Set();
+  private actorTaskState =
+      new Map<number, ObservableValueImpl<ActorTaskState>>();
 
   constructor(public webClient: GlicWebClient, windowProxy: WindowProxy) {
     // TODO(harringtond): Ideally, we could ensure we only process requests from
@@ -325,6 +333,10 @@
       this.unpinTabs = undefined;
       this.unpinAllTabs = undefined;
     }
+
+    if (!state.enableGetContextActor) {
+      this.getContextForActorFromTab = undefined;
+    }
   }
 
   webClientInitialized(
@@ -347,6 +359,14 @@
     return {payload: response};
   }
 
+  setActorTaskState(taskId: number, state: ActorTaskState): void {
+    this.getActorTaskState(taskId).assignAndSignal(state);
+
+    if (state === ActorTaskState.STOPPED) {
+      this.actorTaskState.delete(taskId);
+    }
+  }
+
   onRequestReceived(_type: string): void {}
   onRequestHandlerException(_type: string): void {}
   onRequestCompleted(_type: string): void {}
@@ -420,6 +440,13 @@
     return convertTabContextResultFromPrivate(result.tabContextResult);
   }
 
+  async getContextForActorFromTab?
+      (tabId: string, options: TabContextOptions): Promise<TabContextResult> {
+    const result = await this.sender.requestWithResponse(
+        'glicBrowserGetContextForActorFromTab', {tabId, options});
+    return convertTabContextResultFromPrivate(result.tabContextResult);
+  }
+
   async createTask?(): Promise<number> {
     const result = await this.sender.requestWithResponse(
         'glicBrowserCreateTask', undefined);
@@ -456,6 +483,20 @@
     return convertTabContextResultFromPrivate(response.tabContextResult);
   }
 
+  getActorTaskState(taskId: number): ObservableValueImpl<ActorTaskState> {
+    const stateObs = this.actorTaskState.get(taskId);
+    if (stateObs) {
+      return stateObs;
+    }
+    // TODO(mcnee): The client could pass an id that will never have
+    // state updates (e.g. the task already finished and we cleared the old
+    // observable in setActorTaskState). Consider removing these cases from the
+    // map when all subscribers are removed.
+    const newObs = ObservableValueImpl.withNoValue<ActorTaskState>();
+    this.actorTaskState.set(taskId, newObs);
+    return newObs;
+  }
+
   async resizeWindow(
       width: number, height: number,
       options?: ResizeWindowOptions): Promise<void> {
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
index 01bb100..ab8d447 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
@@ -16,10 +16,10 @@
 
 import type {BrowserProxy} from '../browser_proxy.js';
 import {ContentSettingsType} from '../content_settings_types.mojom-webui.js';
-import type {FocusedTabData as FocusedTabDataMojo, GetPinCandidatesOptions as GetPinCandidatesOptionsMojo, GetTabContextOptions as TabContextOptionsMojo, OpenPanelInfo as OpenPanelInfoMojo, OpenSettingsOptions as OpenSettingsOptionsMojo, PanelOpeningData as PanelOpeningDataMojo, PanelState as PanelStateMojo, PinCandidate as PinCandidateMojo, PinCandidatesObserver, ScrollToSelector as ScrollToSelectorMojo, TabContext as TabContextMojo, TabData as TabDataMojo, WebClientHandlerInterface, WebClientInterface, ZeroStateSuggestionsOptions as ZeroStateSuggestionsOptionsMojo, ZeroStateSuggestionsV2 as ZeroStateSuggestionsV2Mojo} from '../glic.mojom-webui.js';
+import type {ActorTaskState as ActorTaskStateMojo, FocusedTabData as FocusedTabDataMojo, GetPinCandidatesOptions as GetPinCandidatesOptionsMojo, GetTabContextOptions as TabContextOptionsMojo, OpenPanelInfo as OpenPanelInfoMojo, OpenSettingsOptions as OpenSettingsOptionsMojo, PanelOpeningData as PanelOpeningDataMojo, PanelState as PanelStateMojo, PinCandidate as PinCandidateMojo, PinCandidatesObserver, ScrollToSelector as ScrollToSelectorMojo, TabContext as TabContextMojo, TabData as TabDataMojo, WebClientHandlerInterface, WebClientInterface, ZeroStateSuggestionsOptions as ZeroStateSuggestionsOptionsMojo, ZeroStateSuggestionsV2 as ZeroStateSuggestionsV2Mojo} from '../glic.mojom-webui.js';
 import {PinCandidatesObserverReceiver, SettingsPageField as SettingsPageFieldMojo, WebClientHandlerRemote, WebClientMode, WebClientReceiver} from '../glic.mojom-webui.js';
 import type {HostCapability as HostCapabilityMojo} from '../glic.mojom-webui.js';
-import type {ActInFocusedTabParams, DraggableArea, GetPinCandidatesOptions, HostCapability, Journal, OpenSettingsOptions, PageMetadata, PanelOpeningData, PanelState, Screenshot, ScrollToParams, TabContextOptions, WebPageData, ZeroStateSuggestions, ZeroStateSuggestionsOptions, ZeroStateSuggestionsV2} from '../glic_api/glic_api.js';
+import type {ActInFocusedTabParams, ActorTaskState, DraggableArea, GetPinCandidatesOptions, HostCapability, Journal, OpenSettingsOptions, PageMetadata, PanelOpeningData, PanelState, Screenshot, ScrollToParams, TabContextOptions, WebPageData, ZeroStateSuggestions, ZeroStateSuggestionsOptions, ZeroStateSuggestionsV2} from '../glic_api/glic_api.js';
 import {ActInFocusedTabErrorReason, CaptureScreenshotErrorReason, CreateTaskErrorReason, DEFAULT_INNER_TEXT_BYTES_LIMIT, DEFAULT_PDF_SIZE_LIMIT, PerformActionsErrorReason, ScrollToErrorReason} from '../glic_api/glic_api.js';
 import {ObservableValue} from '../observable.js';
 import type {ObservableValueReadOnly} from '../observable.js';
@@ -231,6 +231,13 @@
         'glicWebClientZeroStateSuggestionsChanged',
         {suggestions: suggestions, options: options});
   }
+
+  notifyActorTaskStateChanged(taskId: number, state: ActorTaskStateMojo): void {
+    const clientState = state as number as ActorTaskState;
+    this.sender.requestNoResponse(
+        'glicWebClientNotifyActorTaskStateChanged',
+        {taskId, state: clientState});
+  }
 }
 
 class PinCandidatesObserverImpl implements PinCandidatesObserver {
@@ -410,6 +417,24 @@
     };
   }
 
+  async glicBrowserGetContextForActorFromTab(
+      request: {tabId: string, options: TabContextOptions},
+      extras: ResponseExtras):
+      Promise<{tabContextResult: TabContextResultPrivate}> {
+    const {result: {errorReason, tabContext}} =
+        await this.handler.getContextForActorFromTab(
+            tabIdFromClient(request.tabId),
+            tabContextOptionsFromClient(request.options));
+    if (!tabContext) {
+      throw new Error(`tabContext failed: ${errorReason}`);
+    }
+    const tabContextResult = tabContextToClient(tabContext, extras);
+
+    return {
+      tabContextResult: tabContextResult,
+    };
+  }
+
   async glicBrowserSetMaximumNumberOfPinnedTabs(request: {
     requestedMax: number,
   }): Promise<{effectiveMax: number}> {
diff --git a/chrome/browser/resources/glic/glic_api_impl/request_types.ts b/chrome/browser/resources/glic/glic_api_impl/request_types.ts
index 6503e30..449a977c 100644
--- a/chrome/browser/resources/glic/glic_api_impl/request_types.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/request_types.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {type WebClientInitialState} from '../glic.mojom-webui.js';
-import type {ActInFocusedTabParams, ActInFocusedTabResult, AnnotatedPageData, ChromeVersion, DraggableArea, ErrorReasonTypes, ErrorWithReason, FocusedTabDataHasFocus, FocusedTabDataHasNoFocus, GetPinCandidatesOptions, HostCapability, Journal, OpenPanelInfo, OpenSettingsOptions, PageMetadata, PanelOpeningData, PanelState, PdfDocumentData, PinCandidate, Screenshot, ScrollToParams, TabContextOptions, TabContextResult, TabData, UserProfileInfo, ZeroStateSuggestions, ZeroStateSuggestionsOptions, ZeroStateSuggestionsV2} from '../glic_api/glic_api.js';
+import type {ActInFocusedTabParams, ActInFocusedTabResult, ActorTaskState, AnnotatedPageData, ChromeVersion, DraggableArea, ErrorReasonTypes, ErrorWithReason, FocusedTabDataHasFocus, FocusedTabDataHasNoFocus, GetPinCandidatesOptions, HostCapability, Journal, OpenPanelInfo, OpenSettingsOptions, PageMetadata, PanelOpeningData, PanelState, PdfDocumentData, PinCandidate, Screenshot, ScrollToParams, TabContextOptions, TabContextResult, TabData, UserProfileInfo, ZeroStateSuggestions, ZeroStateSuggestionsOptions, ZeroStateSuggestionsV2} from '../glic_api/glic_api.js';
 
 /*
 This file defines messages sent over postMessage in-between the Glic WebUI
@@ -85,6 +85,15 @@
       tabContextResult: TabContextResultPrivate,
     },
   };
+  glicBrowserGetContextForActorFromTab: {
+    request: {
+      tabId: string,
+      options: TabContextOptions,
+    },
+    response: {
+      tabContextResult: TabContextResultPrivate,
+    },
+  };
   glicBrowserSetMaximumNumberOfPinnedTabs: {
     request: {
       requestedMax: number,
@@ -421,6 +430,12 @@
       options: ZeroStateSuggestionsOptions,
     },
   };
+  glicWebClientNotifyActorTaskStateChanged: {
+    request: {
+      taskId: number,
+      state: ActorTaskState,
+    },
+  };
 }
 
 
@@ -445,6 +460,7 @@
     GetModelQualityClientId: 0,
     GetContextFromFocusedTab: 0,
     GetContextFromTab: 0,
+    GetContextForActorFromTab: 0,
     SetMaximumNumberOfPinnedTabs: 0,
     ActInFocusedTab: 0,
     StopActorTask: 0,
diff --git a/chrome/browser/resources/glic/glic_app_controller.ts b/chrome/browser/resources/glic/glic_app_controller.ts
index 99781018..ff09079 100644
--- a/chrome/browser/resources/glic/glic_app_controller.ts
+++ b/chrome/browser/resources/glic/glic_app_controller.ts
@@ -94,7 +94,7 @@
   AWAITING_NOTIFY_PANEL_WILL_OPEN = 4,
   MAX_VALUE = AWAITING_NOTIFY_PANEL_WILL_OPEN,
 }
-// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:LoadingStage)
+// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:LoadingStage,//tools/metrics/histograms/metadata/glic/histograms.xml:LoadingStage)
 
 export class GlicAppController implements PageInterface, WebviewDelegate,
                                           ApiHostEmbedder {
@@ -123,6 +123,7 @@
   private enteredUnresponsiveTimestampMs?: number;
   // Loading stage, affects metrics only.
   private loadingStage: LoadingStage = LoadingStage.NOT_LOADING;
+  private loadingStageStartTimestampMs?: DOMHighResTimeStamp;
 
   state: WebUiState|undefined;
 
@@ -323,7 +324,7 @@
       WebUiState.kReady,
       {
         onEnter: () => {
-          this.loadingStage = LoadingStage.NOT_LOADING;
+          this.trackLoadingStageEnd();
           $.guestPanel.classList.toggle('show-header', false);
           this.showPanel('guestPanel');
         },
@@ -386,11 +387,36 @@
     this.load();
   }
 
+  private trackLoadingStageStart(newStage: LoadingStage) {
+    this.loadingStage = newStage;
+    this.loadingStageStartTimestampMs = performance.now();
+  }
+
+  private trackLoadingStageEnd() {
+    if (this.loadingStage === LoadingStage.NOT_LOADING) {
+      return;
+    }
+
+    chrome.metricsPrivate.recordMediumTime(
+        'Glic.Host.LoadingStageDuration.' +
+            LoadingStage[this.getLoadingStage()],
+        Math.floor(performance.now() - this.loadingStageStartTimestampMs!));
+    this.loadingStage = LoadingStage.NOT_LOADING;
+  }
+
+  private getLoadingStage(): LoadingStage {
+    if (this.loadingStage === LoadingStage.LOADING_WEB_CLIENT &&
+        this.webview?.waitingOnPanelWillOpen()) {
+      return LoadingStage.AWAITING_NOTIFY_PANEL_WILL_OPEN;
+    }
+    return this.loadingStage;
+  }
+
   private async load(): Promise<void> {
     // profileReadyState isn't available right away. Wait until it's ready.
-    this.loadingStage = LoadingStage.AWAITING_PROFILE_READY;
+    this.trackLoadingStageStart(LoadingStage.AWAITING_PROFILE_READY);
     await this.profileReadyInitialState.promise;
-    this.loadingStage = LoadingStage.NOT_LOADING;
+    this.trackLoadingStageEnd();
 
     const readyState = this.profileReadyState;
     switch (readyState) {
@@ -410,9 +436,9 @@
 
     // Blocking on cookie syncing here introduces latency, we should consider
     // ways to avoid it.
-    this.loadingStage = LoadingStage.AWAITING_COOKIE_SYNC;
+    this.trackLoadingStageStart(LoadingStage.AWAITING_COOKIE_SYNC);
     const {result} = await this.browserProxy.handler.prepareForClient();
-    this.loadingStage = LoadingStage.NOT_LOADING;
+    this.trackLoadingStageEnd();
 
     switch (result) {
       case PrepareForClientResult.kSuccess:
@@ -427,7 +453,7 @@
     }
 
     // Load the web client only after cookie sync is complete.
-    this.loadingStage = LoadingStage.LOADING_WEB_CLIENT;
+    this.trackLoadingStageStart(LoadingStage.LOADING_WEB_CLIENT);
     this.destroyWebview();
     this.webview = new WebviewController(
         $.webviewContainer, this.browserProxy, this, this,
@@ -476,17 +502,12 @@
       }
 
       if (this.state !== WebUiState.kReady) {
-        let loadingStage = this.loadingStage;
-        if (loadingStage === LoadingStage.LOADING_WEB_CLIENT &&
-            this.webview?.waitingOnPanelWillOpen()) {
-          loadingStage = LoadingStage.AWAITING_NOTIFY_PANEL_WILL_OPEN;
-        }
         chrome.metricsPrivate.recordEnumerationValue(
-            'Glic.Host.LoadingTimedOut', loadingStage,
+            'Glic.Host.LoadingTimedOut', this.getLoadingStage(),
             LoadingStage.MAX_VALUE + 1);
         this.webview?.onLoadTimeOut();
       }
-      this.loadingStage = LoadingStage.NOT_LOADING;
+      this.trackLoadingStageEnd();
     }, kMaxWaitTimeMs - kMinHoldLoadingTimeMs);
   }
 
@@ -576,6 +597,7 @@
   webClientReady(): void {
     if (this.state === WebUiState.kBeginLoad ||
         this.state === WebUiState.kFinishLoading) {
+      this.trackLoadingStageEnd();
       this.setState(WebUiState.kReady);
     } else if (this.state === WebUiState.kShowLoading) {
       this.setState(WebUiState.kHoldLoading);
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
index bf5a3c8b..8c1a67a 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
+++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
@@ -28,6 +28,16 @@
     background-color: #1F1F1F;
   }
 
+  :host([enable-aim-searchbox]) .results-pane {
+    /*
+     * If AIM searchbox is enabled, make the results pane the full height of
+     * the side panel.
+     */
+    height: 100%;
+    inset-block-start: 0;
+    position: absolute;
+  }
+
   /* Set z-index to hide results to prevent ghost frames when reshowing. */
   :host([is-loading-results]) #results {
     z-index: 0;
@@ -72,6 +82,11 @@
     --color-searchbox-ghost-loader-loading-bar-2: #ECEDEF;
   }
 
+  /* Hide the old searchbox when the AIM searchbox is enabled. */
+  :host([enable-aim-searchbox]) #searchboxContainer {
+    display: none;
+  }
+
   :host([dark-mode]) #searchboxContainer {
     background-color: #1F1F1F;
     /* Colors used in the cr-searchbox results dropdown */
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
index b006bb2..37e846c 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
+++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
@@ -78,6 +78,11 @@
         type: Boolean,
         value: false,
       },
+      enableAimSearchbox: {
+        reflectToAttribute: true,
+        type: Boolean,
+        value: () => loadTimeData.getBoolean('enableAimSearchbox'),
+      },
       enableCsbMotionTweaks: {
         reflectToAttribute: true,
         type: Boolean,
@@ -209,6 +214,8 @@
   declare private pageContentType: PageContentType;
   // Whether this is an in flight request to autocomplete.
   declare private autocompleteRequestStarted: boolean;
+  // Whether the AIM searchbox is enabled via feature flag.
+  declare private enableAimSearchbox: boolean;
   declare private isErrorPageVisible: boolean;
   // Whether the results iframe is currently loading. This needs to be done via
   // browser because the iframe is cross-origin. Default true since the side
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index e65e4a4..ab0f678 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -49,6 +49,7 @@
     "//chrome/browser/new_tab_page/modules/v2/authentication:mojo_bindings_ts__generator",
     "//chrome/browser/new_tab_page/modules/v2/calendar:mojo_bindings_ts__generator",
     "//chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption:mojo_bindings_ts__generator",
+    "//chrome/browser/new_tab_page/modules/v2/tab_groups:mojo_bindings_ts__generator",
     "//chrome/browser/ui/webui/customize_buttons:mojo_bindings_ts__generator",
     "//chrome/browser/ui/webui/new_tab_page:mojo_bindings_ts__generator",
     "//chrome/browser/ui/webui/new_tab_page/composebox:mojo_bindings_ts__generator",
@@ -66,6 +67,7 @@
     "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/calendar/outlook_calendar.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/url_visit_types.mojom-webui.ts",
+    "$root_gen_dir/chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/ui/webui/ntp_microsoft_auth/ntp_microsoft_auth_shared_ui.mojom-webui.ts",
     "$root_gen_dir/chrome/browser/ui/webui/customize_buttons/customize_buttons.mojom-webui.ts",
diff --git a/chrome/browser/resources/new_tab_page/composebox/composebox.css b/chrome/browser/resources/new_tab_page/composebox/composebox.css
index f298fb01..8dc6c27 100644
--- a/chrome/browser/resources/new_tab_page/composebox/composebox.css
+++ b/chrome/browser/resources/new_tab_page/composebox/composebox.css
@@ -74,6 +74,7 @@
   --cr-button-background-color: var(--ntp-composebox-background-color);
   --cr-button-border-color: var(--color-new-tab-page-composebox-font);
   --cr-button-text-color: var(--color-new-tab-page-composebox-font);
+  font-size: 14px;
 }
 
 #composebox {
@@ -107,6 +108,10 @@
   width: 100%;
 }
 
+:host-context([dir='rtl']) #inputContainer {
+  padding: 0 var(--input-left-spacing) var(--input-bottom-spacing) var(--text-input-right-spacing);
+}
+
 #input {
   animation: color-change 3s infinite;
   background-color: inherit;
@@ -190,6 +195,11 @@
   }
 }
 
+:host-context([dir='rtl']) .action-icon {
+  left: 16px;
+  right: unset;
+}
+
 #cancelIcon {
   --cr-icon-button-fill-color:
       var(--color-new-tab-page-composebox-cancel-button);
diff --git a/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts b/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts
index 849940d..fa5f22b 100644
--- a/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts
+++ b/chrome/browser/resources/new_tab_page/composebox/composebox.html.ts
@@ -18,11 +18,14 @@
     <div id="errorScrim">
       <p>${this.errorMessage_}</p>
       <cr-button id="dismissErrorButton"
-        @click="${this.onDismissErrorButtonClick_}">$i18n{dismissButton}
+          @click="${this.onDismissErrorButtonClick_}">
+        <cr-icon icon="cr:close" slot="prefix-icon"></cr-icon>
+        <div>$i18n{dismissButton}</div>
       </cr-button>
     </div>
   `: ''}
-  <div id="composebox" tabindex="-1" @keydown="${this.onKeydown_}">
+  <div id="composebox" tabindex="-1" @keydown="${this.onKeydown_}"
+      ?inert=${this.showErrorScrim_}>
     <div id="inputContainer">
       <ntp-composebox-file-carousel
         id="carousel"
@@ -47,25 +50,25 @@
             class="upload-icon no-overlap"
             id="fileUploadButton"
             iron-icon="composebox:fileUpload"
-            title="$i18n{composeboxFileUploadButtonTitle}"
+            title="$i18n{composeboxPdfUploadButtonTitle}"
             .disabled="${this.inputsDisabled_}"
             @click="${this.openFileUpload_}">
         </cr-icon-button>
       </div>
     </div>
     <cr-icon-button
-        class="action-icon icon-clear"
-        id="cancelIcon"
-        title="${this.computeCancelButtonTitle_()}"
-        @click="${this.onCancelClick_}">
-    </cr-icon-button>
-    <cr-icon-button
       class="action-icon icon-arrow-upward"
       id="submitIcon"
       title="$i18n{composeboxSubmitButtonTitle}"
       @click="${this.onSubmitClick_}"
       ?disabled="${!this.submitEnabled_}">
     </cr-icon-button>
+    <cr-icon-button
+        class="action-icon icon-clear"
+        id="cancelIcon"
+        title="${this.computeCancelButtonTitle_()}"
+        @click="${this.onCancelClick_}">
+    </cr-icon-button>
   </div>
   <input type="file"
       accept="${this.imageFileTypes_}"
diff --git a/chrome/browser/resources/new_tab_page/composebox/composebox.ts b/chrome/browser/resources/new_tab_page/composebox/composebox.ts
index c35bae2..fcb4c625 100644
--- a/chrome/browser/resources/new_tab_page/composebox/composebox.ts
+++ b/chrome/browser/resources/new_tab_page/composebox/composebox.ts
@@ -189,6 +189,18 @@
     }
   }
 
+  override updated(changedProperties: PropertyValues<this>) {
+    if ((changedProperties as Map<PropertyKey, unknown>)
+            .has('showErrorScrim_') &&
+        this.showErrorScrim_) {
+      const dismissErrorButton =
+          this.shadowRoot.querySelector<HTMLElement>('#dismissErrorButton');
+      if (dismissErrorButton) {
+        dismissErrorButton.focus();
+      }
+    }
+  }
+
   getText() {
     return this.$.input.value;
   }
@@ -233,6 +245,7 @@
         this.errorMessage_ = file.size === 0 ?
             this.i18n('composeboxFileUploadInvalidEmptySize') :
             this.i18n('composeboxFileUploadInvalidTooLarge');
+        input.value = '';
         return;
       } else {
         const fileBuffer = await file.arrayBuffer();
diff --git a/chrome/browser/resources/new_tab_page/lazy_load.ts b/chrome/browser/resources/new_tab_page/lazy_load.ts
index 332b345..500a5ab 100644
--- a/chrome/browser/resources/new_tab_page/lazy_load.ts
+++ b/chrome/browser/resources/new_tab_page/lazy_load.ts
@@ -57,6 +57,7 @@
 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 {ModuleElement as TabGroupsModuleElement, tabGroupsDescriptor} from './modules/v2/tab_groups/module.js';
+export {TabGroupsProxyImpl} from './modules/v2/tab_groups/tab_groups_proxy.js';
 export {NtpPromoProxy, NtpPromoProxyImpl} from './ntp_promo/ntp_promo_proxy.js';
 export {NtpSinglePromoElement} from './ntp_promo/ntp_single_promo.js';
 export {VoiceSearchOverlayElement} from './voice_search_overlay.js';
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css
index 7bb990cb6..9fa8e468 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.css
@@ -11,3 +11,103 @@
   height: 100%;
   width: 100%;
 }
+
+@media (forced-colors: active) {
+  /* Set outline since background isn't visible in hcm */
+  a {
+    border-radius: var(--ntp-module-item-border-radius);
+    outline: var(--cr-border-hcm);
+   }
+
+  .tab-group {
+    overflow: visible;
+  }
+}
+
+:host-context(.focus-outline-visible) a:focus,
+a:focus-visible {
+  box-shadow: var(--ntp-focus-shadow);
+  outline: none;
+}
+
+#tabGroups {
+  background-color: var(--color-new-tab-page-module-item-background);
+  border-radius: var(--ntp-module-item-border-radius);
+  margin: 8px;
+}
+
+.tab-group {
+  align-items: center;
+  display: flex;
+  height: 56px;
+  position: relative;
+  text-decoration: none;
+  overflow: hidden;
+}
+
+.tab-group:hover #hoverLayer {
+  background: var(--color-new-tab-page-module-item-background-hovered);
+  display: block;
+  inset: 0;
+  pointer-events: none;
+  position: absolute;
+}
+
+#hoverLayer {
+  display: none;
+}
+
+.tab-group:first-of-type {
+  border-radius: var(--ntp-module-item-border-radius)
+      var(--ntp-module-item-border-radius) 0 0;
+  padding-top: var(--ntp-module-first-element-top-padding);
+}
+
+.tab-group:last-of-type {
+  border-radius: 0 0 var(--ntp-module-item-border-radius)
+      var(--ntp-module-item-border-radius);
+  padding-bottom: var(--ntp-module-first-element-top-padding);
+}
+
+.icon-container {
+  align-items: center;
+  background-color: var(--color-new-tab-page-module-icon-background);
+  border-radius: 8px;
+  display: flex;
+  flex-shrink: 0;
+  height: var(--ntp-module-icon-size);
+  justify-content: center;
+  margin-inline: 8px;
+  position: relative;
+  width: var(--ntp-module-icon-size);
+}
+
+.tab-group-icon {
+  height: 24px;
+  width: 24px;
+}
+
+.tab-group-info {
+  min-width: 0;
+  padding-inline-end: 16px;
+}
+
+.tab-group-title,
+.tab-group-description {
+  overflow: hidden;
+  position: relative;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.tab-group-title {
+  color: var(--color-new-tab-page-primary-foreground);
+  font-size: var(--ntp-module-text-size);
+  line-height: var(--ntp-module-line-height);
+}
+
+.tab-group-description {
+  color: var(--color-new-tab-page-secondary-foreground);
+  font-size: var(--ntp-module-secondary-text-size);
+  line-height: var(--ntp-module-secondary-line-height);
+}
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html
index 56338562..18953a95 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.html
@@ -4,3 +4,16 @@
     more-actions-text="${this.i18nRecursive(
         '', 'modulesMoreActions', 'modulesTabGroupsTitle')}">
 </ntp-module-header-v2>
+<div id="tabGroups">
+  ${this.getTabGroups_().map(item => html`
+    <a class="tab-group" href="${item.url.url}">
+      <div id="hoverLayer"></div>
+      <icon-container class="icon-container">
+        <img is="cr-auto-img" class="tab-group-icon" draggable="false">
+      </icon-container>
+      <div class="tab-group-info">
+        <div class="tab-group-title">${item.title}</div>
+      </div>
+    </a>
+  `)}
+</div>
\ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts
index ffb49e5..3b656043 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/module.ts
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_grid/cr_grid.js';
 import 'chrome://resources/cr_elements/cr_auto_img/cr_auto_img.js';
 import '/strings.m.js';
 import '../module_header.js';
@@ -10,11 +9,15 @@
 import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import {I18nMixinLit} from '../../../i18n_setup.js';
+import type {TabGroup} from '../../../tab_groups.mojom-webui.js';
 import {ModuleDescriptor} from '../../module_descriptor.js';
 import type {MenuItem} from '../module_header.js';
 
 import {getCss} from './module.css.js';
 import {getHtml} from './module.html.js';
+import {TabGroupsProxyImpl} from './tab_groups_proxy.js';
+
+export const MAX_TAB_GROUPS = 4;
 
 const ModuleElementBase = I18nMixinLit(CrLitElement);
 
@@ -35,6 +38,14 @@
     return getHtml.bind(this)();
   }
 
+  static override get properties() {
+    return {
+      tabGroups: {type: Object},
+    };
+  }
+
+  accessor tabGroups: TabGroup[] = [];
+
   protected getMenuItemGroups_(): MenuItem[][] {
     return [
       [
@@ -65,12 +76,26 @@
       ],
     ];
   }
+
+  protected getTabGroups_(): TabGroup[] {
+    return this.tabGroups.slice(0, MAX_TAB_GROUPS);
+  }
 }
 
 customElements.define(ModuleElement.is, ModuleElement);
 
-async function createElement(): Promise<HTMLElement> {
-  return new Promise<ModuleElement>((resolve) => resolve(new ModuleElement()));
+async function createElement(): Promise<ModuleElement|null> {
+  const {tabGroups} =
+      await TabGroupsProxyImpl.getInstance().handler.getTabGroups();
+  if (!tabGroups || tabGroups.length === 0) {
+    // TODO(crbug.com/431278744): Show zero-state card.
+    return null;
+  }
+
+  const element = new ModuleElement();
+  element.tabGroups = tabGroups;
+
+  return element;
 }
 
 export const tabGroupsDescriptor: ModuleDescriptor = new ModuleDescriptor(
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups.gni b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups.gni
index e05a666..645be1de 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups.gni
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups.gni
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 # List of files that don't need to be passed to html_to_wrapper().
-tab_groups_ts_files = []
+tab_groups_ts_files = [ "modules/v2/tab_groups/tab_groups_proxy.ts" ]
 
 # List of files that should be passed to html_to_wrapper().
 tab_groups_web_component_files = [ "modules/v2/tab_groups/module.ts" ]
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups_proxy.ts b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups_proxy.ts
new file mode 100644
index 0000000..07dcb155
--- /dev/null
+++ b/chrome/browser/resources/new_tab_page/modules/v2/tab_groups/tab_groups_proxy.ts
@@ -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.
+
+import type {PageHandlerRemote} from '../../../tab_groups.mojom-webui.js';
+import {PageHandler} from '../../../tab_groups.mojom-webui.js';
+
+export interface TabGroupsProxy {
+  handler: PageHandlerRemote;
+}
+
+export class TabGroupsProxyImpl implements TabGroupsProxy {
+  handler: PageHandlerRemote;
+
+  constructor(handler: PageHandlerRemote) {
+    this.handler = handler;
+  }
+
+  static getInstance(): TabGroupsProxy {
+    return instance ||
+        (instance = new TabGroupsProxyImpl(PageHandler.getRemote()));
+  }
+
+  static setInstance(newInstance: TabGroupsProxy) {
+    instance = newInstance;
+  }
+}
+
+let instance: TabGroupsProxy|null = null;
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page.gni b/chrome/browser/resources/new_tab_page/new_tab_page.gni
index 37b5ab5..aaf70f2b 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page.gni
+++ b/chrome/browser/resources/new_tab_page/new_tab_page.gni
@@ -64,6 +64,7 @@
     "new_tab_page.mojom-webui.js",
     "ntp_microsoft_auth_shared_ui.mojom-webui.js",
     "outlook_calendar.mojom-webui.js",
+    "tab_groups.mojom-webui.js",
     "url_visit_types.mojom-webui.js",
   ]
 
diff --git a/chrome/browser/resources/password_manager/BUILD.gn b/chrome/browser/resources/password_manager/BUILD.gn
index f1aa8e12..c23cb09 100644
--- a/chrome/browser/resources/password_manager/BUILD.gn
+++ b/chrome/browser/resources/password_manager/BUILD.gn
@@ -132,8 +132,14 @@
     "//ui/webui/resources/cr_components/help_bubble:build_ts",
     "//ui/webui/resources/cr_elements:build_ts",
     "//ui/webui/resources/js:build_ts",
+    "//ui/webui/resources/mojo:build_ts",
   ]
 
+  mojo_files_deps = [
+    "//chrome/browser/ui/webui/password_manager:mojo_bindings_ts__generator",
+  ]
+  mojo_files = [ "$root_gen_dir/chrome/browser/ui/webui/password_manager/password_manager.mojom-webui.ts" ]
+
   ts_path_mappings =
       [ "/shared/settings/*|" + rebase_path(
             "$root_gen_dir/chrome/browser/resources/settings_shared/tsc/*",
diff --git a/chrome/browser/resources/password_manager/password_change_details.html b/chrome/browser/resources/password_manager/password_change_details.html
index b6cc20a..ebb552244 100644
--- a/chrome/browser/resources/password_manager/password_change_details.html
+++ b/chrome/browser/resources/password_manager/password_change_details.html
@@ -81,7 +81,6 @@
 </div>
 <div class="cr-row first">
   <div class="flex cr-padded-text">
-    <div>$i18n{passwordChangeSettingLabel}</div>
     <div class="cr-padded-text cr-secondary-text">
       $i18n{passwordChangeSettingSubLabel}
     </div>
diff --git a/chrome/browser/resources/password_manager/password_manager_proxy.ts b/chrome/browser/resources/password_manager/password_manager_proxy.ts
index 9da7f830..04a25735 100644
--- a/chrome/browser/resources/password_manager/password_manager_proxy.ts
+++ b/chrome/browser/resources/password_manager/password_manager_proxy.ts
@@ -4,9 +4,14 @@
 
 /**
  * @fileoverview PasswordManagerProxy is an abstraction over
- * chrome.passwordsPrivate which facilitates testing.
+ * chrome.passwordsPrivate and a Mojo remote. It is intended to facilitate
+ * testing. The chrome.passwordsPrivate API is being migrated to use Mojo.
  */
 
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
+
+import {PageCallbackRouter, PageHandlerFactory, PageHandlerRemote} from './password_manager.mojom-webui.js';
+
 export type BlockedSite = chrome.passwordsPrivate.ExceptionEntry;
 
 export type AccountStorageEnabledStateChangedListener =
@@ -422,6 +427,16 @@
  * Implementation that accesses the private API.
  */
 export class PasswordManagerImpl implements PasswordManagerProxy {
+  callbackRouter: PageCallbackRouter = new PageCallbackRouter();
+  handler: PageHandlerRemote = new PageHandlerRemote();
+
+  constructor() {
+    const factory = PageHandlerFactory.getRemote();
+    factory.createPageHandler(
+        this.callbackRouter.$.bindNewPipeAndPassRemote(),
+        this.handler.$.bindNewPipeAndPassReceiver());
+  }
+
   addSavedPasswordListChangedListener(listener: CredentialsChangedListener) {
     chrome.passwordsPrivate.onSavedPasswordsListChanged.addListener(listener);
   }
@@ -674,15 +689,18 @@
   }
 
   deleteAllPasswordManagerData() {
-    return chrome.passwordsPrivate.deleteAllPasswordManagerData();
+    return loadTimeData.getBoolean('enablePasswordManagerMojoApi') ?
+        this.handler.deleteAllPasswordManagerData().then(
+            result => result.success) :
+        chrome.passwordsPrivate.deleteAllPasswordManagerData();
   }
 
   static getInstance(): PasswordManagerProxy {
     return instance || (instance = new PasswordManagerImpl());
   }
 
-  static setInstance(obj: PasswordManagerProxy) {
-    instance = obj;
+  static setInstance(proxy: PasswordManagerProxy) {
+    instance = proxy;
   }
 }
 
diff --git a/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.html b/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.html
index 8634919..2770e3a 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.html
+++ b/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.html
@@ -21,6 +21,7 @@
     background: var(--tabs-background-color);
     border-right: 1px solid var(--tabs-border-color);
     transition: min-width 0.2s ease-in-out;
+    overflow-y: auto;
   }
 
   :host([collapsed]) #sidebar-container {
@@ -57,27 +58,50 @@
     display: none;
   }
 
-  #tablist ::slotted(.group-header) {
+  #tablist ::slotted(.settings-category-header)::before,
+  #tablist ::slotted(.setting-header)::before {
+    content: '';
+    display: inline-block;
+    flex-shrink: 0;
+    width: 24px;
+    height: 24px;
+    margin-right: 8px;
+    background-color: var(--tabs-unselected-text-color);
+    mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 17l5-5-5-5v10z"></path></svg>');
+    mask-size: contain;
+    mask-repeat: no-repeat;
+    mask-position: center;
+  }
+
+  #tablist ::slotted(.settings-category-header:not([collapsed]))::before,
+  #tablist ::slotted(.setting-header:not([collapsed]))::before {
+    mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 10l5 5 5-5H7z"></path></svg>');
+  }
+
+  #tablist ::slotted(.settings-category-header) {
+    cursor: pointer;
+    display: flex;
+    align-items: center;
     font-weight: 900;
     text-transform: uppercase;
     color: var(--cr-primary-text-color);
-    padding: 16px 24px 8px 24px;
-    pointer-events: none;
+    padding: 16px 24px 8px;
   }
 
-  #tablist ::slotted(.sub-group-header) {
+  #tablist ::slotted(.setting-header) {
+    cursor: pointer;
+    display: flex;
+    align-items: center;
     font-weight: 700;
     color: var(--cr-primary-text-color);
     padding: 12px 24px 4px 32px;
-    pointer-events: none;
   }
 
   #tablist ::slotted(:not([role='heading'])) {
-    padding: 0 24px 0 32px;
+    padding: 0 24px 0 56px;
     height: 32px;
     display: flex;
     align-items: center;
-    border-radius: 0 16px 16px 0;
     border-inline-start: 4px solid transparent;
   }
 
@@ -97,14 +121,21 @@
     border-inline-start-color: var(--cr-active-text-color);
   }
 
+  #tablist ::slotted(.hidden-by-group) {
+    display: none;
+  }
+
   #tablist:focus {
     outline: none;
   }
 
   #tabpanels {
+    box-shadow: none;
+    display: inline-block;
     flex-grow: 1;
     overflow: auto;
-    padding: 12px 24px;
+    vertical-align: top;
+    padding: 4px 9px 4px 10px;
   }
 
   #tabpanels ::slotted(*) {
@@ -113,9 +144,9 @@
 
   #tabpanels ::slotted([selected]) {
     display: block;
+    padding: 12px 24px;
   }
 </style>
-
 <div id="sidebar-container">
   <button id="sidebar-visibility-button" aria-label="Toggle Sidebar Visibility">
     <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
diff --git a/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.ts b/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.ts
index ea5de28..6f3eae9 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.ts
+++ b/chrome/browser/resources/privacy_sandbox/internals/cr_frame_list.ts
@@ -1,7 +1,6 @@
 // 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 {assert} from '//resources/js/assert.js';
 import {CustomElement} from '//resources/js/custom_element.js';
 import {FocusOutlineManager} from '//resources/js/focus_outline_manager.js';
@@ -23,32 +22,104 @@
     return ['selected-index', 'collapsed'];
   }
 
-  private tabs_: HTMLElement;
-  private panels_: HTMLElement;
+  private tabs_: HTMLSlotElement;
   private focusOutlineManager_: FocusOutlineManager;
 
   constructor() {
     super();
-
-    this.tabs_ = this.getRequiredElement('#tablist');
-    this.panels_ = this.getRequiredElement('#tabpanels');
+    this.tabs_ = this.getRequiredElement<HTMLSlotElement>('slot[name=tab]');
     this.focusOutlineManager_ = FocusOutlineManager.forDocument(document);
+  }
+
+  connectedCallback() {
     this.setupEventListeners();
+    this.initializeOrProcessTabs();
+  }
+
+  /**
+   * Sets up tabs: adds icons to headings, selects the active tab, and updates
+   * visibility.
+   */
+  initializeOrProcessTabs() {
+    const tabs = this.getSlottedTabs_();
+    if (tabs.length === 0) {
+      return;
+    }
+
+    const iconTemplate = this.shadowRoot!.querySelector<HTMLElement>(
+        '#icon-templates > .toggle-icon');
+
+    tabs.forEach(tab => {
+      if (tab.getAttribute('role') === 'heading') {
+        tab.removeAttribute('collapsed');
+        if (iconTemplate && !tab.querySelector('.toggle-icon')) {
+          tab.prepend(iconTemplate.cloneNode(true));
+        }
+      }
+    });
+
+    const foundIndex = tabs.findIndex(
+        tab => tab.hasAttribute('selected') ||
+            tab.getAttribute('role') !== 'heading');
+    const selectedIndex = foundIndex !== -1 ? foundIndex : 0;
+
+    if (!this.hasAttribute('selected-index')) {
+      this.setAttribute('selected-index', selectedIndex.toString());
+    }
+    this.updateAllTabsVisibility();
+  }
+
+  /** Shows or hides tabs based on whether their parent group is collapsed. */
+  updateAllTabsVisibility() {
+    const tabs = this.getSlottedTabs_();
+    let groupIsCollapsed = false;
+    let subGroupIsCollapsed = false;
+
+    for (const tab of tabs) {
+      const isGroupHeader = tab.classList.contains('settings-category-header');
+      const isSubGroupHeader = tab.classList.contains('setting-header');
+
+      if (isGroupHeader) {
+        groupIsCollapsed = tab.hasAttribute('collapsed');
+        subGroupIsCollapsed = false;
+        continue;
+      }
+
+      if (isSubGroupHeader) {
+        tab.classList.toggle('hidden-by-group', groupIsCollapsed);
+        subGroupIsCollapsed = tab.hasAttribute('collapsed');
+        continue;
+      }
+
+      tab.classList.toggle(
+          'hidden-by-group', groupIsCollapsed || subGroupIsCollapsed);
+    }
   }
 
   setupEventListeners() {
-    // Add event listener for keyboard navigation and tab clicks.
-    this.tabs_.addEventListener('keydown', e => this.onKeydown_(e));
-    this.tabs_.addEventListener('click', (e: MouseEvent) => {
-      const tabs = this.getSlottedTabs_();
-      const clickedTab = (e.target as HTMLElement).closest('[slot="tab"]');
+    this.tabs_.addEventListener(
+        'slotchange', () => this.initializeOrProcessTabs());
 
-      // Ignore clicks on non-selectable headings or outside of a tab.
-      if (!clickedTab || clickedTab.getAttribute('role') === 'heading') {
+    // Add event listener for keyboard navigation and tab clicks.
+    const tablist = this.getRequiredElement('#tablist');
+    tablist.addEventListener('keydown', e => this.onKeydown_(e));
+    tablist.addEventListener('click', (e: MouseEvent) => {
+      const clickedElement =
+          (e.target as HTMLElement).closest<HTMLElement>('[slot="tab"]');
+      if (!clickedElement) {
         return;
       }
 
-      const index = tabs.findIndex(tab => tab === clickedTab);
+      // Clicking a heading toggles its collapsed state.
+      if (clickedElement.getAttribute('role') === 'heading') {
+        clickedElement.toggleAttribute('collapsed');
+        this.updateAllTabsVisibility();
+        return;
+      }
+
+      // Clicking a regular tab selects it.
+      const index =
+          this.getSlottedTabs_().findIndex(tab => tab === clickedElement);
       if (index !== -1) {
         this.setAttribute('selected-index', index.toString());
       }
@@ -58,24 +129,6 @@
         .addEventListener('click', () => this.toggleSidebar_());
   }
 
-  connectedCallback() {
-    // Avoid re-setting the index if it's already been set.
-    if (this.hasAttribute('selected-index')) {
-      return;
-    }
-
-    const tabs = this.getSlottedTabs_();
-    let initialIndex = tabs.findIndex(tab => tab.hasAttribute('selected'));
-
-    // If no tab is pre-selected, find the first non-heading tab to select.
-    if (initialIndex === -1) {
-      initialIndex =
-          tabs.findIndex(tab => tab.getAttribute('role') !== 'heading');
-    }
-    this.setAttribute(
-        'selected-index', (initialIndex > -1 ? initialIndex : 0).toString());
-  }
-
   attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
     if (name === 'selected-index') {
       const newIndex = Number(newValue);
@@ -88,7 +141,6 @@
       this.getSlottedTabs_().forEach((tab: HTMLElement, index: number) => {
         const isSelected = index === newIndex;
         tab.toggleAttribute('selected', isSelected);
-
         // Non-selectable heading tabs should not get focus or ARIA attributes.
         if (tab.getAttribute('role') !== 'heading') {
           // Update tabIndex for a11y
@@ -114,14 +166,13 @@
   }
 
   private getSlottedTabs_(): HTMLElement[] {
-    const slot = this.tabs_.querySelector('slot');
-    return slot ? (Array.from(slot.assignedElements()) as HTMLElement[]) : [];
+    return this.tabs_.assignedElements() as HTMLElement[];
   }
 
   private getSlottedPanels_(): Element[] {
-    const slot =
-        this.panels_.querySelector<HTMLSlotElement>('slot[name=panel]');
-    return slot ? Array.from(slot.assignedElements()) : [];
+    const panelsSlot: HTMLSlotElement =
+        this.getRequiredElement('slot[name=panel]');
+    return Array.from(panelsSlot.assignedElements());
   }
 
   private onKeydown_(e: KeyboardEvent) {
@@ -147,7 +198,6 @@
 
     const tabs = this.getSlottedTabs_();
     const tabsCount = tabs.length;
-
     if (tabsCount === 0) {
       return;
     }
@@ -165,7 +215,6 @@
     }
 
     this.setAttribute('selected-index', newIndex.toString());
-
     // Show focus outline since we used the keyboard.
     this.focusOutlineManager_.visible = true;
   }
diff --git a/chrome/browser/resources/privacy_sandbox/internals/internals_page.html b/chrome/browser/resources/privacy_sandbox/internals/internals_page.html
index 35d7b683..03878594 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/internals_page.html
+++ b/chrome/browser/resources/privacy_sandbox/internals/internals_page.html
@@ -10,20 +10,20 @@
     width: 100%;
   }
 
-div.content-settings {
-  display: grid;
-  gap: 24px;
-  grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));
-}
+  div.content-settings {
+    display: grid;
+    gap: 24px;
+    grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));
+  }
 
-content-setting-pattern-source {
-  display: grid;
-  box-shadow: rgba(0, 0, 0, 0.3) 0 1px 2px 0,
-                 rgba(0, 0, 0, 0.15) 0 2px 6px 2px;
-  background: white;
-  border-radius: 8px;
-}
+  content-setting-pattern-source {
+    display: grid;
+    box-shadow: rgba(0, 0, 0, 0.3) 0 1px 2px 0,
+      rgba(0, 0, 0, 0.15) 0 2px 6px 2px;
+    background: white;
+    border-radius: 8px;
+  }
 </style>
 
 <cr-frame-list id="ps-page">
-</cr-frame-list>
+</cr-frame-list>
\ No newline at end of file
diff --git a/chrome/browser/resources/privacy_sandbox/internals/internals_page.ts b/chrome/browser/resources/privacy_sandbox/internals/internals_page.ts
index 5e36fdc..f653b9c0 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/internals_page.ts
+++ b/chrome/browser/resources/privacy_sandbox/internals/internals_page.ts
@@ -12,6 +12,7 @@
 
 import {CustomElement} from 'chrome://resources/js/custom_element.js';
 
+import {contentSettingGroups} from './content_settings_groups.js';
 import {ContentSettingsType} from './content_settings_types.mojom-webui.js';
 import type {CrFrameListElement} from './cr_frame_list.js';
 import {getTemplate} from './internals_page.html.js';
@@ -143,21 +144,43 @@
 
     const allTabsInDom =
         Array.from(frameList.querySelectorAll<HTMLElement>('[slot="tab"]'));
-    const index = allTabsInDom.findIndex(
+    let index = allTabsInDom.findIndex(
         (tab: HTMLElement) => tab.dataset['pageName'] === pageName);
 
+    // If no direct match, fall back to the pre-selected tab.
+    if (index === -1) {
+      index = allTabsInDom.findIndex(
+          (tab: HTMLElement) => tab.hasAttribute('selected'));
+    }
+
+    // If a match is found, update the UI. Otherwise, do nothing.
     if (index !== -1) {
       frameList.setAttribute('selected-index', index.toString());
-    } else {
-      frameList.setAttribute('selected-index', '0');
     }
   }
 
   // Create the DOM elements needed for the pref pages
   createLayoutForPrefPages() {
+    const headerTab = document.createElement('div');
+    headerTab.innerText = 'Prefs';
+    headerTab.className = 'settings-category-header';
+    headerTab.setAttribute('role', 'heading');
+    headerTab.setAttribute('slot', 'tab');
+    this.tabBox.appendChild(headerTab);
+
+    const headerPanel = document.createElement('div');
+    headerPanel.setAttribute('slot', 'panel');
+    this.tabBox.appendChild(headerPanel);
+
     prefPagesToCreate.forEach((pageToCreate) => {
       const prefPage = document.createElement('pref-page');
       prefPage.pageConfig = pageToCreate;
+
+      // The specific pref-page instance to be the default.
+      if (pageToCreate.id === 'tracking-protection') {
+        prefPage.isDefault = true;
+      }
+
       this.tabBox.append(prefPage);
     });
   }
@@ -192,42 +215,80 @@
   async load() {
     this.createLayoutForPrefPages();
     this.loadAndDisplayPrefs();
-    const csPanelContainers = new Map<string, HTMLElement>();
+    const csPanels = new Map<ContentSettingsType, HTMLElement>();
     const handler = this.browserProxy_.handler;
     const shouldShowTpcdMetadataGrants =
         this.browserProxy_.shouldShowTpcdMetadataGrants();
 
-    for (let i = ContentSettingsType.MIN_VALUE;
-         i <= ContentSettingsType.MAX_VALUE; i++) {
+    const addHeaderToTabBox = (name: string, className: string) => {
+      const headerTab = document.createElement('div');
+      headerTab.innerText = name;
+      headerTab.className = className;
+      headerTab.setAttribute('role', 'heading');
+      headerTab.setAttribute('slot', 'tab');
+      this.tabBox.appendChild(headerTab);
+
+      const headerPanel = document.createElement('div');
+      headerPanel.setAttribute('slot', 'panel');
+      this.tabBox.appendChild(headerPanel);
+    };
+
+    const addContentSetting = (setting: ContentSettingsType) => {
       // Controls the visibility of the TPCD_METADATA_GRANTS tab.
-      if (ContentSettingsType[i] === 'TPCD_METADATA_GRANTS' &&
+      if (setting === ContentSettingsType.TPCD_METADATA_GRANTS &&
           !shouldShowTpcdMetadataGrants) {
-        continue;
+        return;
+      }
+      if (setting === ContentSettingsType.DEFAULT) {
+        return;
       }
       const tab = document.createElement('div');
-      tab.innerText = ContentSettingsType[i];
+      tab.innerText = ContentSettingsType[setting];
       tab.setAttribute('slot', 'tab');
-      tab.dataset['pageName'] = ContentSettingsType[i].toLowerCase();
+      tab.dataset['pageName'] = ContentSettingsType[setting].toLowerCase();
       this.tabBox.appendChild(tab);
 
       const panel = document.createElement('div');
       panel.setAttribute('slot', 'panel');
-      panel.setAttribute('title', ContentSettingsType[i]);
+      panel.setAttribute('title', ContentSettingsType[setting]);
+
       const panelTitle = document.createElement('h2');
-      panelTitle.innerText = ContentSettingsType[i];
+      panelTitle.innerText = ContentSettingsType[setting];
+      panel.appendChild(panelTitle);
+
       const contentSettingsContainer = document.createElement('div');
       contentSettingsContainer.classList.add('content-settings');
-      panel.appendChild(panelTitle);
       panel.appendChild(contentSettingsContainer);
       this.tabBox.appendChild(panel);
 
-      csPanelContainers.set(ContentSettingsType[i], contentSettingsContainer);
-    }
+      csPanels.set(setting, contentSettingsContainer);
+    };
 
+    addHeaderToTabBox('Content Settings', 'settings-category-header');
+
+    const otherSettings = new Set<ContentSettingsType>();
     for (let i = ContentSettingsType.MIN_VALUE;
          i <= ContentSettingsType.MAX_VALUE; i++) {
+      if (i !== ContentSettingsType.DEFAULT) {
+        otherSettings.add(i);
+      }
+    }
+
+    contentSettingGroups.forEach(group => {
+      addHeaderToTabBox(group.name, 'setting-header');
+      group.settings.forEach(setting => {
+        addContentSetting(setting);
+        otherSettings.delete(setting);
+      });
+    });
+
+    if (otherSettings.size > 0) {
+      otherSettings.forEach(setting => addContentSetting(setting));
+    }
+
+    for (const [setting, panel] of csPanels.entries()) {
       let mojoResponse;
-      if (i === ContentSettingsType.TPCD_METADATA_GRANTS) {
+      if (setting === ContentSettingsType.TPCD_METADATA_GRANTS) {
         // Prevents the TPCD Metadata Grants tab from loading and rendering if
         // its flag is disabled.
         if (!shouldShowTpcdMetadataGrants) {
@@ -236,10 +297,9 @@
         // This one is special and can't be read through readContentSettings().
         mojoResponse = await handler.getTpcdMetadataGrants();
       } else {
-        mojoResponse = await handler.readContentSettings(i);
+        mojoResponse = await handler.readContentSettings(setting);
       }
       mojoResponse.contentSettings.forEach((cs: any) => {
-        const panel = csPanelContainers.get(ContentSettingsType[i])!;
         const item = document.createElement('content-setting-pattern-source');
         panel.appendChild(item);
         item.configure(handler, cs);
diff --git a/chrome/browser/resources/privacy_sandbox/internals/pref_page.ts b/chrome/browser/resources/privacy_sandbox/internals/pref_page.ts
index cc4098d..7b9b543 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/pref_page.ts
+++ b/chrome/browser/resources/privacy_sandbox/internals/pref_page.ts
@@ -21,6 +21,7 @@
 
 export class PrefPage extends CustomElement {
   pageConfig: PrivacySandboxInternalsPrefPageConfig|null = null;
+  isDefault: boolean = false;
 
   static get is() {
     return 'pref-page';
@@ -42,22 +43,22 @@
     pageTemplateEl.innerHTML = getTemplate();
 
     // Customize the tab slot for the left sidebar
-    const pageTab =
-        pageTemplateEl.content.querySelector<HTMLElement>('[slot="tab"]')!;
+    const fragment = pageTemplateEl.content.cloneNode(true) as DocumentFragment;
+    const pageTab = fragment.querySelector<HTMLElement>('[slot="tab"]')!;
     pageTab.textContent = this.pageConfig.title;
     pageTab.dataset['pageName'] = this.pageConfig.id;
     pageTab.id = this.pageConfig.id + '-prefs-tab';
 
-    // Create the pref panels where prefs will be inserted
-    const pagePanel =
-        pageTemplateEl.content.querySelector<HTMLElement>('[slot="panel"]')!;
+    // Add the 'selected' attribute for the default page.
+    if (this.isDefault) {
+      pageTab.toggleAttribute('selected', true);
+    }
+    const pagePanel = fragment.querySelector<HTMLElement>('[slot="panel"]')!;
     this.pageConfig.prefGroups.forEach((prefGroup) => {
       const template =
-          pageTemplateEl.content.querySelector<HTMLTemplateElement>(
-              '#pref-group-template')!;
+          fragment.querySelector<HTMLTemplateElement>('#pref-group-template')!;
       const clone = template.content.cloneNode(true) as DocumentFragment;
 
-      // Populate the fields in the pref group template and add it to the page.
       clone.querySelector('.pref-group-title')!.textContent = prefGroup.title;
       clone.querySelector<HTMLElement>('.pref-group-panel')!.id =
           prefGroup.id + '-prefs-panel';
@@ -66,7 +67,6 @@
 
     // Move the nodes from the fragment to be direct children of the parent.
     // This makes them available for slotting by <cr-frame-list>.
-    const fragment = pageTemplateEl.content.cloneNode(true);
     parent.appendChild(fragment);
 
     // Remove the <pref-page> node from the DOM after its children have been
diff --git a/chrome/browser/resources/privacy_sandbox/internals/style.css b/chrome/browser/resources/privacy_sandbox/internals/style.css
index ea7e332e..487cdf6 100644
--- a/chrome/browser/resources/privacy_sandbox/internals/style.css
+++ b/chrome/browser/resources/privacy_sandbox/internals/style.css
@@ -19,3 +19,20 @@
   font-size: 1.5rem;
   margin-bottom: 0px;
 }
+
+html,
+body {
+  height: 100%;
+  margin: 0;
+  overflow: hidden;
+}
+
+body {
+  display: flex;
+  flex-direction: column;
+}
+
+main {
+  flex-grow: 1;
+  overflow: hidden;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 6c57795..b59672a 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -105,8 +105,10 @@
     "on_startup_page/startup_url_dialog.ts",
     "on_startup_page/startup_url_entry.ts",
     "on_startup_page/startup_urls_page.ts",
+    "people_page/people_page_index.ts",
     "people_page/people_page.ts",
     "people_page/signout_dialog.ts",
+    "people_page/sync_controls_page.ts",
     "people_page/sync_controls.ts",
     "people_page/sync_encryption_options.ts",
     "people_page/sync_page.ts",
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index bc7e0fcb..0d5a165 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -1,23 +1,10 @@
     <style include="cr-shared-style settings-page-styles cr-hidden-style">
-      :host([is-subpage-animating]) {
-        /* Prevent an unwanted horizontal scrollbar when transitioning back from
-         * a sub-page. */
-        overflow: hidden;
-      }
-
       :host(:not([in-search-mode])) settings-section:not([active]) {
         display: none;
       }
     </style>
-    <template is="dom-if" if="[[showBasicPage_(currentRoute_, inSearchMode)]]"
-        restamp>
-      <div id="basicPage">
-        <template is="dom-if" if="[[showPage_(pageVisibility_.people)]]" restamp>
-          <settings-section page-title="$i18n{peoplePageTitle}"
-              section="people">
-            <settings-people-page prefs="{{prefs}}"></settings-people-page>
-          </settings-section>
-        </template>
+    <div id="basicPage">
+      <template is="dom-if" if="[[isPrivacyGuideAvailable]]" restamp>
         <settings-section id="privacyGuidePromoSection" page-title=""
             hidden$="[[!showPrivacyGuidePromo_]]" nest-under-section="privacy"
             no-search>
@@ -25,24 +12,24 @@
               prefs="{{prefs}}">
           </settings-privacy-guide-promo>
         </settings-section>
-        <!--  TODO(crbug.com/40267370): Add a test to basic_page_test.ts
-        to check that settings-safety-hub-entry-point is not visible
-        in the guest mode. -->
-        <template is="dom-if" if="[[showPage_(pageVisibility_.safetyHub)]]"
-            restamp>
-          <settings-section page-title="$i18n{safetyHub}"
-              section="safetyHubEntryPoint" nest-under-section="privacy"
-              id="safetyHubEntryPointSection">
-            <settings-safety-hub-entry-point></settings-safety-hub-entry-point>
-          </settings-section>
-        </template>
-        <template is="dom-if" if="[[showPage_(pageVisibility_.privacy)]]"
-            restamp>
-          <settings-section page-title="$i18n{privacyPageTitle}"
-              section="privacy">
-            <settings-privacy-page prefs="{{prefs}}">
-            </settings-privacy-page>
-          </settings-section>
-        </template>
-      </div>
-    </template>
+      </template>
+      <!--  TODO(crbug.com/40267370): Add a test to basic_page_test.ts
+      to check that settings-safety-hub-entry-point is not visible
+      in the guest mode. -->
+      <template is="dom-if" if="[[showPage_(pageVisibility_.safetyHub)]]"
+          restamp>
+        <settings-section page-title="$i18n{safetyHub}"
+            section="safetyHubEntryPoint" nest-under-section="privacy"
+            id="safetyHubEntryPointSection">
+          <settings-safety-hub-entry-point></settings-safety-hub-entry-point>
+        </settings-section>
+      </template>
+      <template is="dom-if" if="[[showPage_(pageVisibility_.privacy)]]"
+          restamp>
+        <settings-section page-title="$i18n{privacyPageTitle}"
+            section="privacy">
+          <settings-privacy-page prefs="{{prefs}}">
+          </settings-privacy-page>
+        </settings-section>
+      </template>
+    </div>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts
index e40f75c..84e48e76 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.ts
+++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -14,7 +14,6 @@
 import '../privacy_page/privacy_guide/privacy_guide_promo.js';
 import '../privacy_page/privacy_page.js';
 import '../safety_hub/safety_hub_entry_point.js';
-import '../people_page/people_page.js';
 import '../settings_page/settings_section.js';
 import '../settings_page_styles.css.js';
 
@@ -22,14 +21,8 @@
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// clang-format off
-// <if expr="is_chromeos">
-import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
-// </if>
-// clang-format on
 
 
-import {loadTimeData} from '../i18n_setup.js';
 import {pageVisibility} from '../page_visibility.js';
 import type {PageVisibility} from '../page_visibility.js';
 import {PrivacyGuideAvailabilityMixin} from '../privacy_page/privacy_guide/privacy_guide_availability_mixin.js';
@@ -90,15 +83,6 @@
       },
 
       currentRoute_: Object,
-
-      /**
-       * Used to avoid handling a new toggle while currently toggling.
-       */
-      advancedTogglingInProgress_: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true,
-      },
     };
   }
 
@@ -112,19 +96,11 @@
   declare inSearchMode: boolean;
 
   declare private currentRoute_: Route;
-  declare private advancedTogglingInProgress_: boolean;
   declare private showPrivacyGuidePromo_: boolean;
   private privacyGuidePromoWasShown_: boolean;
   private privacyGuideBrowserProxy_: PrivacyGuideBrowserProxy =
       PrivacyGuideBrowserProxyImpl.getInstance();
 
-  override ready() {
-    super.ready();
-
-    this.setAttribute('role', 'main');
-  }
-
-
   override connectedCallback() {
     super.connectedCallback();
 
@@ -142,8 +118,7 @@
 
   /** Overrides MainPageMixin method. */
   override containsRoute(route: Route|null): boolean {
-    return !route || routes.BASIC.contains(route) ||
-        (routes.ADVANCED && routes.ADVANCED.contains(route));
+    return !route || routes.PRIVACY.contains(route);
   }
 
   private showPage_(visibility?: boolean): boolean {
@@ -167,46 +142,13 @@
     }
   }
 
-  /**
-   * SettingsPlugin implementation
-   * Queues a task to search the basic sections, then another for the advanced
-   * sections.
-   * @param query The text to search for.
-   * @return A signal indicating that searching finished.
-   */
+  // SettingsPlugin implementation.
   async searchContents(query: string) {
     const basicPage = this.shadowRoot!.querySelector<HTMLElement>('#basicPage');
     assert(basicPage);
     const request = await getSearchManager().search(query, basicPage);
     return request.getSearchResult();
   }
-
-  // <if expr="is_chromeos">
-  private onOpenChromeOsLanguagesSettingsClick_() {
-    OpenWindowProxyImpl.getInstance().openUrl(
-        loadTimeData.getString('osSettingsLanguagesPageUrl'));
-  }
-  // </if>
-
-  private fire_(eventName: string, detail: any) {
-    this.dispatchEvent(
-        new CustomEvent(eventName, {bubbles: true, composed: true, detail}));
-  }
-
-  /**
-   * @return Whether to show #basicPage. This is an optimization to lazy render
-   *     #basicPage only when a section/subpage within it is being shown, or
-   *     when in search mode.
-   * TODO(crbug.com/424223101): Make <settings-basic-page> as a whole lazy
-   * rendered and remove showBasicPage_()
-   */
-  private showBasicPage_(): boolean {
-    if (this.currentRoute_ === undefined) {
-      return false;
-    }
-
-    return this.inSearchMode || routes.BASIC.contains(this.currentRoute_);
-  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.html
index ec9a746..07953d79 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.html
@@ -82,12 +82,20 @@
         <div slot="label" class="label">$i18n{searchHistory}</div>
       </cr-link-row>
       <cr-link-row id="myActivityLink" external using-slotted-label
-          class$="[[getMyActivityLinkCssClass_(isGoogleDse_)]]"
+          class$="[[getMyActivityLinkCssClass_(isGoogleDse_, syncStatus_)]]"
           hidden="[[!shouldShowMyActivityLink_(syncStatus_)]]"
           sub-label="$i18n{manageInYourGoogleAccount}"
           on-click="onMyActivityLinkClick_">
         <div slot="label" class="label">$i18n{myActivity}</div>
       </cr-link-row>
+      <!-- TODO(rbug.com/432207975): Translate geminiAppsActivity strings. -->
+      <cr-link-row id="geminiAppsActivityLink" external using-slotted-label
+          class$="[[getGeminiAppsActivityLinkCssClass_(isGoogleDse_)]]"
+          hidden="[[!shouldShowGeminiAppsActivityLink_(syncStatus_)]]"
+          sub-label="$i18n{manageInYourGeminiAppsActivity}"
+          on-click="onGeminiAppsActivityClick_">
+        <div slot="label" class="label">$i18n{geminiAppsActivity}</div>
+      </cr-link-row>
       <div id="nonGoogleSearchHistoryLink" class="cr-row first last-link-row"
           hidden="[[isGoogleDse_]]">
         <div class="flex cr-padded-text">
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts b/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts
index 9f7bc04..4809fa3 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/other_google_data_dialog.ts
@@ -40,6 +40,7 @@
     passwordManagerLink: CrLinkRowElement,
     myActivityLink: CrLinkRowElement,
     nonGoogleSearchHistoryLink: HTMLElement,
+    geminiAppsActivityLink: CrLinkRowElement,
   };
 }
 
@@ -142,6 +143,11 @@
         'Settings.DeleteBrowsingData.GoogleSearchHistoryLinkClick');
   }
 
+  private onGeminiAppsActivityClick_() {
+    OpenWindowProxyImpl.getInstance().openUrl(
+        loadTimeData.getString('myActivityGeminiAppsUrl'));
+  }
+
   private shouldShowMyActivityLink_() {
     return isSignedIn(this.syncStatus_);
   }
@@ -150,13 +156,24 @@
     return isSignedIn(this.syncStatus_) && this.isGoogleDse_;
   }
 
+  private shouldShowGeminiAppsActivityLink_() {
+    return isSignedIn(this.syncStatus_) &&
+        loadTimeData.getBoolean('showGlicSettings') &&
+        loadTimeData.getBoolean('enableBrowsingHistoryActorIntegrationM1');
+  }
+
   private getMyActivityLinkCssClass_() {
-    if (!this.isGoogleDse_) {
+    // TODO (crbug.com/432676120) Make CSS class assignment more robust.
+    if (!this.isGoogleDse_ || this.shouldShowGeminiAppsActivityLink_()) {
       return 'middle-link-row';
     }
     return 'last-link-row';
   }
 
+  private getGeminiAppsActivityLinkCssClass_() {
+    return this.isGoogleDse_ ? 'last-link-row' : 'middle-link-row';
+  }
+
   private getPasswordsLinkCssClass_() {
     if (this.isGoogleDse_ && !isSignedIn(this.syncStatus_)) {
       return 'only-link-row';
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index 992c0cdd..8f451fc 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -62,7 +62,7 @@
 import './people_page/manage_profile.js';
 // </if>
 import './people_page/signout_dialog.js';
-import './people_page/sync_controls.js';
+import './people_page/sync_controls_page.js';
 import './people_page/sync_page.js';
 // Sections
 import './a11y_page/a11y_page_index.js';
diff --git a/chrome/browser/resources/settings/people_page/account_page.html b/chrome/browser/resources/settings/people_page/account_page.html
index f390ad7..081ec70 100644
--- a/chrome/browser/resources/settings/people_page/account_page.html
+++ b/chrome/browser/resources/settings/people_page/account_page.html
@@ -1,5 +1,7 @@
-<settings-sync-account-control sync-status="[[syncStatus]]"
-    prefs="{{prefs}}" hide-banner>
-</settings-sync-account-control>
-<settings-sync-controls sync-status="[[syncStatus]]">
-</settings-sync-controls>
+<settings-subpage page-title="$i18n{accountPageTitle}">
+  <settings-sync-account-control sync-status="[[syncStatus_]]"
+      prefs="{{prefs}}" hide-banner>
+  </settings-sync-account-control>
+  <settings-sync-controls sync-status="[[syncStatus_]]">
+  </settings-sync-controls>
+</settings-subpage>
diff --git a/chrome/browser/resources/settings/people_page/account_page.ts b/chrome/browser/resources/settings/people_page/account_page.ts
index 9acd7ee..b21cdd2 100644
--- a/chrome/browser/resources/settings/people_page/account_page.ts
+++ b/chrome/browser/resources/settings/people_page/account_page.ts
@@ -9,18 +9,25 @@
  * controls and advanced sync settings.
  */
 import './sync_account_control.js';
+import '../settings_page/settings_subpage.js';
 
 import type {SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
-import {SignedInState} from '/shared/settings/people_page/sync_browser_proxy.js';
+import {SignedInState, SyncBrowserProxyImpl} from '/shared/settings/people_page/sync_browser_proxy.js';
+import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
+import {assert} from 'chrome://resources/js/assert.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {loadTimeData} from '../i18n_setup.js';
 import {routes} from '../route.js';
 import {Router} from '../router.js';
+import {SettingsViewMixin} from '../settings_page/settings_view_mixin.js';
 
 import {getTemplate} from './account_page.html.js';
 
-export class SettingsAccountPageElement extends PolymerElement {
+const SettingsAccountPageElementBase =
+    SettingsViewMixin(WebUiListenerMixin(PolymerElement));
+
+export class SettingsAccountPageElement extends SettingsAccountPageElementBase {
   static get is() {
     return 'settings-account-page';
   }
@@ -34,23 +41,41 @@
       /**
        * The current sync status.
        */
-      syncStatus: {
-        type: Object,
-        observer: 'syncStatusChanged_',
-      },
+      syncStatus_: {type: Object},
     };
   }
 
-  declare syncStatus: SyncStatus|null;
+  declare private syncStatus_: SyncStatus|null;
 
-  private syncStatusChanged_() {
+  override connectedCallback() {
+    super.connectedCallback();
+
+    assert(loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos'));
+
+    SyncBrowserProxyImpl.getInstance().getSyncStatus().then(
+        this.onSyncStatusChanged_.bind(this));
+    this.addWebUiListener(
+        'sync-status-changed', this.onSyncStatusChanged_.bind(this));
+  }
+
+  private onSyncStatusChanged_(syncStatus: SyncStatus) {
+    this.syncStatus_ = syncStatus;
+
+    if (Router.getInstance().getCurrentRoute() !== routes.ACCOUNT) {
+      return;
+    }
+
     // Don't show this page if the user is not signed in.
-    if (!loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos') ||
-        !this.syncStatus ||
-        this.syncStatus.signedInState !== SignedInState.SIGNED_IN) {
+    if (!this.syncStatus_ ||
+        this.syncStatus_.signedInState !== SignedInState.SIGNED_IN) {
       Router.getInstance().navigateTo(routes.PEOPLE);
     }
   }
+
+  // SettingsViewMixin implementation.
+  override focusBackButton() {
+    this.shadowRoot!.querySelector('settings-subpage')!.focusBackButton();
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.html b/chrome/browser/resources/settings/people_page/manage_profile.html
index 759f93c6..9bef2386 100644
--- a/chrome/browser/resources/settings/people_page/manage_profile.html
+++ b/chrome/browser/resources/settings/people_page/manage_profile.html
@@ -70,6 +70,7 @@
   }
 </style>
 
+<settings-subpage page-title="$i18n{editPerson}">
 <div class="cr-row first manage-profile-section">
   <h1 class="cr-title-text">$i18n{nameYourProfile}</h1>
   <div class="content">
@@ -118,3 +119,4 @@
   </div>
   <div class="hr"></div>
 </template>
+</settings-subpage>
diff --git a/chrome/browser/resources/settings/people_page/manage_profile.ts b/chrome/browser/resources/settings/people_page/manage_profile.ts
index f44e4a1..82e7aba 100644
--- a/chrome/browser/resources/settings/people_page/manage_profile.ts
+++ b/chrome/browser/resources/settings/people_page/manage_profile.ts
@@ -11,6 +11,7 @@
 import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js';
 import 'chrome://resources/cr_elements/cr_shared_style.css.js';
 import 'chrome://resources/cr_components/theme_color_picker/theme_color_picker.js';
+import '../settings_page/settings_subpage.js';
 import '../settings_shared.css.js';
 import 'chrome://resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js';
 
@@ -23,14 +24,16 @@
 
 import {loadTimeData} from '../i18n_setup.js';
 import {routes} from '../route.js';
+import type {Route} from '../router.js';
 import {RouteObserverMixin, Router} from '../router.js';
+import {SettingsViewMixin} from '../settings_page/settings_view_mixin.js';
 
 import {getTemplate} from './manage_profile.html.js';
 import type {ManageProfileBrowserProxy} from './manage_profile_browser_proxy.js';
 import {ManageProfileBrowserProxyImpl, ProfileShortcutStatus} from './manage_profile_browser_proxy.js';
 
 const SettingsManageProfileElementBase =
-    RouteObserverMixin(WebUiListenerMixin(PolymerElement));
+    SettingsViewMixin(RouteObserverMixin(WebUiListenerMixin(PolymerElement)));
 
 export interface SettingsManageProfileElement {
   $: {
@@ -132,7 +135,9 @@
         'profile-info-changed', this.onProfileInfoChanged_.bind(this));
   }
 
-  override currentRouteChanged() {
+  override currentRouteChanged(newRoute: Route, oldRoute?: Route) {
+    super.currentRouteChanged(newRoute, oldRoute);
+
     if (Router.getInstance().getCurrentRoute() === routes.MANAGE_PROFILE) {
       if (this.profileName_) {
         this.$.nameInput.value = this.profileName_;
@@ -206,6 +211,11 @@
       this.browserProxy_.removeProfileShortcut();
     }
   }
+
+  // SettingsViewMixin implementation.
+  override focusBackButton() {
+    this.shadowRoot!.querySelector('settings-subpage')!.focusBackButton();
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index c944feef..649c15f 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -65,9 +65,8 @@
         }
       }
     </style>
-    <settings-animated-pages id="pages" section="people"
-        focus-config="[[focusConfig_]]">
-      <div route-path="default">
+    <settings-section>
+      <div>
 <if expr="not is_chromeos">
         <template is="dom-if" if="[[shouldShowSyncAccountControl_(
             syncStatus.syncSystemEnabled)]]">
@@ -159,46 +158,7 @@
 </if>
 
       </div>
-      <template is="dom-if" route-path="/syncSetup">
-        <settings-subpage
-            associated-control="[[$$('#sync-setup')]]"
-            page-title="$i18n{syncPageTitle}"
-            learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}">
-          <settings-sync-page prefs="{{prefs}}" focus-config="[[focusConfig_]]">
-          </settings-sync-page>
-        </settings-subpage>
-      </template>
-
-      <template is="dom-if" route-path="/syncSetup/advanced">
-        <settings-subpage page-title="$i18n{syncAdvancedPageTitle}"
-            associated-control="[[$$('#sync-setup')]]"
-            learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}">
-          <settings-sync-controls sync-status="[[syncStatus]]">
-          </settings-sync-controls>
-        </settings-subpage>
-      </template>
-
-<if expr="not is_chromeos">
-      <template is="dom-if" route-path="/manageProfile">
-        <settings-subpage
-            associated-control=
-                "[[getEditPersonAssocControl_(signinAllowed_)]]"
-            page-title="$i18n{editPerson}">
-          <settings-manage-profile></settings-manage-profile>
-        </settings-subpage>
-      </template>
-
-      <template is="dom-if" if="[[shouldShowAccountSettingsPage_]]" restamp>
-        <template is="dom-if" route-path="/account">
-          <settings-subpage page-title="$i18n{accountPageTitle}">
-            <settings-account-page prefs="{{prefs}}"
-                sync-status="[[syncStatus]]" no-search>
-            </settings-account-page>
-          </settings-subpage>
-        </template>
-      </template>
-</if>
-    </settings-animated-pages>
+    </settings-section>
 
 <if expr="not is_chromeos">
     <template is="dom-if" if="[[showSignoutDialog_]]" restamp>
diff --git a/chrome/browser/resources/settings/people_page/people_page.ts b/chrome/browser/resources/settings/people_page/people_page.ts
index 8fc9c650..1297174 100644
--- a/chrome/browser/resources/settings/people_page/people_page.ts
+++ b/chrome/browser/resources/settings/people_page/people_page.ts
@@ -19,8 +19,7 @@
 import './sync_account_control.js';
 // </if>
 import '../icons.html.js';
-import '../settings_page/settings_animated_pages.js';
-import '../settings_page/settings_subpage.js';
+import '../settings_page/settings_section.js';
 import '../settings_shared.css.js';
 
 import type {ProfileInfo} from '/shared/settings/people_page/profile_info_browser_proxy.js';
@@ -32,17 +31,18 @@
 // </if>
 import type {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
+import {assert} from 'chrome://resources/js/assert.js';
 import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
 import {getImage} from 'chrome://resources/js/icon.js';
 import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
 import {isChromeOS} from 'chrome://resources/js/platform.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {BaseMixin} from '../base_mixin.js';
-import type {FocusConfig} from '../focus_config.js';
 import {loadTimeData} from '../i18n_setup.js';
 import {routes} from '../route.js';
+import type {Route} from '../router.js';
 import {Router} from '../router.js';
+import {SettingsViewMixin} from '../settings_page/settings_view_mixin.js';
 
 // <if expr="not is_chromeos">
 import {RouteObserverMixin} from '../router.js';
@@ -63,11 +63,11 @@
 
 // <if expr="not is_chromeos">
 const SettingsPeoplePageElementBase =
-    RouteObserverMixin(WebUiListenerMixin(BaseMixin(PolymerElement)));
+    SettingsViewMixin(RouteObserverMixin(WebUiListenerMixin(PolymerElement)));
 // </if>
 // <if expr="is_chromeos">
 const SettingsPeoplePageElementBase =
-    WebUiListenerMixin(BaseMixin(PolymerElement));
+    SettingsViewMixin(WebUiListenerMixin(PolymerElement));
 // </if>
 
 export class SettingsPeoplePageElement extends SettingsPeoplePageElementBase {
@@ -186,27 +186,6 @@
 
       showSignoutDialog_: Boolean,
       // </if>
-
-
-      focusConfig_: {
-        type: Object,
-        value() {
-          const map = new Map();
-          if (routes.SYNC) {
-            map.set(routes.SYNC.path, '#sync-setup');
-          }
-          // <if expr="not is_chromeos">
-          if (routes.MANAGE_PROFILE) {
-            map.set(
-                routes.MANAGE_PROFILE.path,
-                loadTimeData.getBoolean('signinAllowed') ?
-                    '#edit-profile' :
-                    '#profile-row .subpage-arrow');
-          }
-          // </if>
-          return map;
-        },
-      },
     };
   }
 
@@ -227,8 +206,6 @@
   declare private showSignoutDialog_: boolean;
   // </if>
 
-  declare private focusConfig_: FocusConfig;
-
   private syncBrowserProxy_: SyncBrowserProxy =
       SyncBrowserProxyImpl.getInstance();
 
@@ -272,7 +249,9 @@
   }
 
   // <if expr="not is_chromeos">
-  override currentRouteChanged() {
+  override currentRouteChanged(newRoute: Route, oldRoute?: Route) {
+    super.currentRouteChanged(newRoute, oldRoute);
+
     this.showImportDataDialog_ =
         Router.getInstance().getCurrentRoute() === routes.IMPORT_DATA;
 
@@ -289,12 +268,6 @@
   }
   // </if>
 
-  private getEditPersonAssocControl_(): Element {
-    return this.signinAllowed_ ?
-        this.shadowRoot!.querySelector('#edit-profile')! :
-        this.shadowRoot!.querySelector('#profile-row')!;
-  }
-
   /**
    * Handler for when the profile's icon and name is updated.
    */
@@ -332,7 +305,7 @@
   /**
    * Handler for when the sync state is pushed from the browser.
    */
-  private handleSyncStatus_(syncStatus: SyncStatus|null) {
+  private handleSyncStatus_(syncStatus: SyncStatus) {
     // Sign-in impressions should be recorded only if the sign-in promo is
     // shown. They should be recorder only once, the first time
     // |this.syncStatus| is set.
@@ -429,6 +402,61 @@
     return !!this.syncStatus &&
         this.syncStatus.signedInState === SignedInState.SYNCING;
   }
+
+  // SettingsViewMixin implementation.
+  override getFocusConfig() {
+    const map = new Map();
+    if (routes.SYNC) {
+      map.set(routes.SYNC.path, '#sync-setup');
+    }
+    // <if expr="not is_chromeos">
+    if (routes.MANAGE_PROFILE) {
+      map.set(
+          routes.MANAGE_PROFILE.path,
+          loadTimeData.getBoolean('signinAllowed') ?
+              '#edit-profile' :
+              '#profile-row .subpage-arrow');
+    }
+    // </if>
+    return map;
+  }
+
+  // SettingsViewMixin implementation.
+  override getAssociatedControlFor(childViewId: string): HTMLElement {
+    const ids = [
+      'sync', 'syncControls',
+      // <if expr="not is_chromeos">
+      'manageProfile', 'account',
+      // </if>
+    ];
+    assert(ids.includes(childViewId));
+
+    let triggerId: string|null = null;
+    switch (childViewId) {
+      case 'sync':
+      case 'syncControls':
+        triggerId = 'sync-setup';
+        break;
+      // <if expr="not is_chromeos">
+      case 'manageProfile':
+        triggerId = this.signinAllowed_ ? 'edit-profile' : 'profile-row';
+        break;
+      case 'account':
+        assert(loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos'));
+        // TODO(crbug.com/429139804): Replace with actual entry point once
+        // implemented.
+        triggerId = 'sync-setup';
+        break;
+        // </if>
+    }
+
+    assert(triggerId);
+
+    const control =
+        this.shadowRoot!.querySelector<HTMLElement>(`#${triggerId}`);
+    assert(control);
+    return control;
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/people_page/people_page_index.html b/chrome/browser/resources/settings/people_page/people_page_index.html
new file mode 100644
index 0000000..d3d97da1
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/people_page_index.html
@@ -0,0 +1,32 @@
+<style include="settings-shared">
+  cr-view-manager [hidden-by-search],
+  cr-view-manager[show-all] [slot=view][data-parent-view-id] {
+    display: none;
+  }
+</style>
+
+<cr-view-manager id="viewManager" class="cr-centered-card-container"
+    show-all$="[[shouldShowAll]]">
+  <settings-people-page slot="view" id="parent" prefs="{{prefs}}">
+  </settings-people-page>
+
+  <settings-sync-page slot="view" id="sync"
+      data-parent-view-id="parent" prefs="{{prefs}}">
+  </settings-sync-page>
+
+  <settings-sync-controls-page slot="view" id="syncControls"
+      data-parent-view-id="parent">
+  </settings-sync-controls-page>
+
+<if expr="not is_chromeos">
+   <settings-manage-profile slot="view" id="manageProfile"
+       data-parent-view-id="parent" profile-name="[[profileName_]]">
+   </settings-manage-profile>
+
+   <template is="dom-if" if="[[shouldShowAccountSettingsPage_]]" restamp>
+     <settings-account-page slot="view" id="account"
+         data-parent-view-id="parent" prefs="{{prefs}}">
+     </settings-account-page>
+   </template>
+</if>
+</cr-view-manager>
diff --git a/chrome/browser/resources/settings/people_page/people_page_index.ts b/chrome/browser/resources/settings/people_page/people_page_index.ts
new file mode 100644
index 0000000..9db7dfd
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/people_page_index.ts
@@ -0,0 +1,114 @@
+// 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 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
+import '/shared/settings/prefs/prefs.js';
+import './people_page.js';
+import '../settings_shared.css.js';
+
+import type {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
+import {assert} from 'chrome://resources/js/assert.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {loadTimeData} from '../i18n_setup.js';
+import {routes} from '../route.js';
+import {RouteObserverMixin} from '../router.js';
+import type {Route} from '../router.js';
+import type {SettingsPlugin} from '../settings_main/settings_plugin.js';
+import {SearchableViewContainerMixin} from '../settings_page/searchable_view_container_mixin.js';
+
+import {getTemplate} from './people_page_index.html.js';
+
+
+export interface SettingsPeoplePageIndexElement {
+  $: {
+    viewManager: CrViewManagerElement,
+  };
+}
+
+const SettingsPeoplePageIndexElementBase =
+    SearchableViewContainerMixin(RouteObserverMixin(PolymerElement));
+
+export class SettingsPeoplePageIndexElement extends
+    SettingsPeoplePageIndexElementBase implements SettingsPlugin {
+  static get is() {
+    return 'settings-people-page-index';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      prefs: Object,
+
+      // <if expr="not is_chromeos">
+      shouldShowAccountSettingsPage_: {
+        type: Boolean,
+        value: () =>
+            loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos'),
+      },
+      // </if>
+    };
+  }
+
+  declare prefs: {[key: string]: any};
+
+  // <if expr="not is_chromeos">
+  declare private shouldShowAccountSettingsPage_: boolean;
+  // </if>
+
+  override currentRouteChanged(newRoute: Route, oldRoute?: Route) {
+    super.currentRouteChanged(newRoute, oldRoute);
+
+    // Need to wait for currentRouteChanged observers on child views to run
+    // first, before switching views.
+    queueMicrotask(() => {
+      switch (newRoute) {
+        case routes.PEOPLE:
+          this.$.viewManager.switchView(
+              'parent', 'no-animation', 'no-animation');
+          break;
+        case routes.BASIC:
+          // Switch back to the default views in case they are part of search
+          // results.
+          this.$.viewManager.switchView(
+              'parent', 'no-animation', 'no-animation');
+          break;
+        case routes.SYNC:
+          this.$.viewManager.switchView('sync', 'no-animation', 'no-animation');
+          break;
+        case routes.SYNC_ADVANCED:
+          this.$.viewManager.switchView(
+              'syncControls', 'no-animation', 'no-animation');
+          break;
+        // <if expr="not is_chromeos">
+        case routes.ACCOUNT:
+          assert(this.shouldShowAccountSettingsPage_);
+          this.$.viewManager.switchView(
+              'account', 'no-animation', 'no-animation');
+          break;
+        case routes.MANAGE_PROFILE:
+          this.$.viewManager.switchView(
+              'manageProfile', 'no-animation', 'no-animation');
+          break;
+        // </if>
+        default:
+          // Nothing to do. Other parent elements are responsible for updating
+          // the displayed contents.
+          break;
+      }
+    });
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'settings-people-page-index': SettingsPeoplePageIndexElement;
+  }
+}
+
+customElements.define(
+    SettingsPeoplePageIndexElement.is, SettingsPeoplePageIndexElement);
diff --git a/chrome/browser/resources/settings/people_page/sync_controls_page.html b/chrome/browser/resources/settings/people_page/sync_controls_page.html
new file mode 100644
index 0000000..7f2e998
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/sync_controls_page.html
@@ -0,0 +1,5 @@
+<settings-subpage page-title="$i18n{syncAdvancedPageTitle}"
+    learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}">
+  <settings-sync-controls sync-status="[[syncStatus_]]">
+  </settings-sync-controls>
+</settings-subpage>
diff --git a/chrome/browser/resources/settings/people_page/sync_controls_page.ts b/chrome/browser/resources/settings/people_page/sync_controls_page.ts
new file mode 100644
index 0000000..222ef1e
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/sync_controls_page.ts
@@ -0,0 +1,64 @@
+// 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 './sync_controls.js';
+import '../settings_page/settings_subpage.js';
+
+import {WebUiListenerMixin} from '//resources/cr_elements/web_ui_listener_mixin.js';
+import type {SyncStatus} from '/shared/settings/people_page/sync_browser_proxy.js';
+import {SyncBrowserProxyImpl} from '/shared/settings/people_page/sync_browser_proxy.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {SettingsViewMixin} from '../settings_page/settings_view_mixin.js';
+
+import {getTemplate} from './sync_controls_page.html.js';
+
+const SettingsSyncControlsPageElementBase =
+    SettingsViewMixin(WebUiListenerMixin(PolymerElement));
+
+export class SettingsSyncControlsPageElement extends
+    SettingsSyncControlsPageElementBase {
+  static get is() {
+    return 'settings-sync-controls-page';
+  }
+
+  static get template() {
+    return getTemplate();
+  }
+
+  static get properties() {
+    return {
+      syncStatus_: {type: Object},
+    };
+  }
+
+  declare private syncStatus_: SyncStatus|null;
+
+  override connectedCallback() {
+    super.connectedCallback();
+
+    SyncBrowserProxyImpl.getInstance().getSyncStatus().then(
+        this.onSyncStatusChanged_.bind(this));
+    this.addWebUiListener(
+        'sync-status-changed', this.onSyncStatusChanged_.bind(this));
+  }
+
+  private onSyncStatusChanged_(syncStatus: SyncStatus) {
+    this.syncStatus_ = syncStatus;
+  }
+
+  // SettingsViewMixin implementation.
+  override focusBackButton() {
+    this.shadowRoot!.querySelector('settings-subpage')!.focusBackButton();
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    'settings-sync-controls-page': SettingsSyncControlsPageElement;
+  }
+}
+
+customElements.define(
+    SettingsSyncControlsPageElement.is, SettingsSyncControlsPageElement);
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index 1121539..02f3d43 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -69,6 +69,8 @@
       }
     </style>
 
+  <settings-subpage page-title="$i18n{syncPageTitle}"
+      learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}">
 <if expr="not is_chromeos">
     <template is="dom-if" if="[[shouldShowSyncAccountControl_(
         syncStatus_.syncSystemEnabled)]]">
@@ -240,3 +242,4 @@
       </cr-dialog>
     </template>
 </if>
+  </settings-subpage>
diff --git a/chrome/browser/resources/settings/people_page/sync_page.ts b/chrome/browser/resources/settings/people_page/sync_page.ts
index da12b8c0..bd2c84b 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.ts
+++ b/chrome/browser/resources/settings/people_page/sync_page.ts
@@ -19,6 +19,7 @@
 
 import './sync_encryption_options.js';
 import '../privacy_page/personalization_options.js';
+import '../settings_page/settings_subpage.js';
 import '../settings_shared.css.js';
 import '../settings_vars.css.js';
 // <if expr="not is_chromeos">
@@ -46,7 +47,9 @@
 import type {SettingsPersonalizationOptionsElement} from '../privacy_page/personalization_options.js';
 // </if>
 
+import type {Route} from '../router.js';
 import {RouteObserverMixin, Router} from '../router.js';
+import {SettingsViewMixin} from '../settings_page/settings_view_mixin.js';
 
 // <if expr="is_chromeos">
 import type {SettingsSyncEncryptionOptionsElement} from './sync_encryption_options.js';
@@ -65,8 +68,8 @@
  * 'settings-sync-page' is the settings page containing sync settings.
  */
 
-const SettingsSyncPageElementBase =
-    RouteObserverMixin(WebUiListenerMixin(I18nMixin(PolymerElement)));
+const SettingsSyncPageElementBase = SettingsViewMixin(
+    RouteObserverMixin(WebUiListenerMixin(I18nMixin(PolymerElement))));
 
 export class SettingsSyncPageElement extends SettingsSyncPageElementBase {
   static get is() {
@@ -392,7 +395,9 @@
   }
   // </if>
 
-  override currentRouteChanged() {
+  override currentRouteChanged(newRoute: Route, oldRoute?: Route) {
+    super.currentRouteChanged(newRoute, oldRoute);
+
     const router = Router.getInstance();
     if (router.getCurrentRoute() === router.getRoutes().SYNC) {
       this.onNavigateToPage_();
@@ -697,6 +702,11 @@
       passphraseInput.focus();
     }
   }
+
+  // SettingsViewMixin implementation.
+  override focusBackButton() {
+    this.shadowRoot!.querySelector('settings-subpage')!.focusBackButton();
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index 259a524..589c12a 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -178,25 +178,33 @@
   r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines');
   r.SEARCH_ENGINES.hasMigratedToPlugin = true;
 
-  if (!loadTimeData.getBoolean('isGuest')) {
+  const visibility = pageVisibility || {};
+
+  if (visibility.people !== false) {
     r.PEOPLE = r.BASIC.createSection(
         '/people', 'people', loadTimeData.getString('peoplePageTitle'));
+    r.PEOPLE.hasMigratedToPlugin = true;
     // <if expr="not is_chromeos">
     r.SIGN_OUT = r.PEOPLE.createChild('/signOut');
     r.SIGN_OUT.isNavigableDialog = true;
+    r.SIGN_OUT.hasMigratedToPlugin = true;
     r.IMPORT_DATA = r.PEOPLE.createChild('/importData');
     r.IMPORT_DATA.isNavigableDialog = true;
+    r.IMPORT_DATA.hasMigratedToPlugin = true;
     if (loadTimeData.getBoolean('replaceSyncPromosWithSignInPromos')) {
       r.ACCOUNT = r.PEOPLE.createChild('/account');
+      r.ACCOUNT.hasMigratedToPlugin = true;
     }
+    r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile');
+    r.MANAGE_PROFILE.hasMigratedToPlugin = true;
     // </if>
 
     r.SYNC = r.PEOPLE.createChild('/syncSetup');
+    r.SYNC.hasMigratedToPlugin = true;
     r.SYNC_ADVANCED = r.SYNC.createChild('/syncSetup/advanced');
+    r.SYNC_ADVANCED.hasMigratedToPlugin = true;
   }
 
-  const visibility = pageVisibility || {};
-
   if (visibility.ai !== false && loadTimeData.getBoolean('showAiPage')) {
     r.AI = r.BASIC.createSection(
         '/ai', 'ai', loadTimeData.getString('aiInnovationsPageTitle'));
@@ -225,13 +233,6 @@
     // </if>
   }
 
-  // <if expr="not is_chromeos">
-  if (visibility.people !== false) {
-    assert(r.PEOPLE);
-    r.MANAGE_PROFILE = r.PEOPLE.createChild('/manageProfile');
-  }
-  // </if>
-
   if (visibility.appearance !== false) {
     r.APPEARANCE = r.BASIC.createSection(
         '/appearance', 'appearance',
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts
index ec3f06c8..bf6617d4 100644
--- a/chrome/browser/resources/settings/settings.ts
+++ b/chrome/browser/resources/settings/settings.ts
@@ -85,6 +85,7 @@
 export {AccountManagerBrowserProxy, AccountManagerBrowserProxyImpl} from './people_page/account_manager_browser_proxy.js';
 // </if>
 export {SettingsPeoplePageElement} from './people_page/people_page.js';
+export {SettingsPeoplePageIndexElement} from './people_page/people_page_index.js';
 // <if expr="not is_chromeos">
 export {SettingsSyncAccountControlElement} from './people_page/sync_account_control.js';
 // </if>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 1ff85d2..2f4806dc 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -56,8 +56,20 @@
 
 <cr-view-manager id="switcher"
     show-all$="[[shouldShowAll_(inSearchMode_, lastRoute_)]]">
+  <template is="dom-if" if="[[showPage_(pageVisibility_.people)]]">
+    <div slot="view" id="people">
+      <template is="dom-if" if="[[renderPlugin_(
+          routes_.PEOPLE, lastRoute_, inSearchMode_)]]">
+        <settings-people-page-index prefs="{{prefs}}"
+            in-search-mode="[[inSearchMode_]]">
+        </settings-people-page-index>
+      </template>
+    </div>
+  </template>
+
   <div slot="view" id="old">
-    <template is="dom-if" if="[[renderBasicPage_(lastRoute_)]]">
+    <template is="dom-if" if="[[renderPlugin_(
+        routes_.PRIVACY, lastRoute_, inSearchMode_)]]">
       <settings-basic-page class="cr-centered-card-container"
           prefs="{{prefs}}" in-search-mode="[[inSearchMode_]]">
       </settings-basic-page>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.ts b/chrome/browser/resources/settings/settings_main/settings_main.ts
index 35ba1b4f..1fb97aa 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.ts
+++ b/chrome/browser/resources/settings/settings_main/settings_main.ts
@@ -16,6 +16,7 @@
 import '../autofill_page/autofill_page_index.js';
 import '../basic_page/basic_page.js';
 import '../on_startup_page/on_startup_page.js';
+import '../people_page/people_page_index.js';
 import '../performance_page/performance_page_index.js';
 import '../reset_page/reset_profile_banner.js';
 import '../search_page/search_page_index.js';
@@ -152,6 +153,8 @@
   override connectedCallback() {
     super.connectedCallback();
 
+    this.setAttribute('role', 'main');
+
     // Request loading of the lazy loaded module within an idle callback.
     requestIdleCallback(() => ensureLazyLoaded());
   }
@@ -194,6 +197,12 @@
     if (!sectionElement) {
       // Wait for any pageVisibility <dom-if>s to render and try again.
       await this.beforeNextRenderPromise_();
+
+      if (this.lastRoute_ !== effectiveRoute || !this.isConnected) {
+        // A newer currentRouteChanged call happened while awaiting or no longer
+        // connected (both can happen in tests). Do nothing.
+        return;
+      }
       sectionElement = this.$.switcher.querySelector(`#${newSection}`);
     }
 
@@ -258,12 +267,7 @@
     });
   }
 
-  private renderBasicPage_(): boolean {
-    return this.lastRoute_ !== routes.ABOUT;
-  }
-
   private renderPlugin_(route: Route): boolean {
-    assert(route.hasMigratedToPlugin);
     return this.inSearchMode_ ||
         (!!this.lastRoute_ && route.contains(this.lastRoute_));
   }
diff --git a/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts b/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts
index 7f3c930..99bcecf 100644
--- a/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts
+++ b/chrome/browser/resources/side_panel/read_anything/menus/highlight_menu.ts
@@ -55,10 +55,10 @@
       title: loadTimeData.getString('wordHighlightTitle'),
       data: chrome.readingMode.wordHighlighting,
     },
-    {
+    ...(chrome.readingMode.isPhraseHighlightingEnabled?[{
       title: loadTimeData.getString('phraseHighlightTitle'),
       data: chrome.readingMode.phraseHighlighting,
-    },
+    }]: []),
     {
       title: loadTimeData.getString('sentenceHighlightTitle'),
       data: chrome.readingMode.sentenceHighlighting,
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 12085e3..5ff9d74 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
@@ -34,7 +34,7 @@
 import type {LetterSpacingMenuElement} from './menus/letter_spacing_menu.js';
 import type {LineSpacingMenuElement} from './menus/line_spacing_menu.js';
 import type {RateMenuElement} from './menus/rate_menu.js';
-import {ReadAloudSettingsChange, ReadAnythingSettingsChange} from './metrics_browser_proxy.js';
+import {ReadAnythingSettingsChange} from './metrics_browser_proxy.js';
 import {ReadAnythingLogger, SpeechControls, TimeFrom} from './read_anything_logger.js';
 import {getCss} from './read_anything_toolbar.css.js';
 import {getHtml} from './read_anything_toolbar.html.js';
@@ -362,13 +362,7 @@
   }
 
   protected getHighlightButtonLabel_(): string {
-    if (chrome.readingMode.isPhraseHighlightingEnabled) {
       return loadTimeData.getString('voiceHighlightLabel');
-    } else {
-      return chrome.readingMode.isHighlightOn() ?
-          loadTimeData.getString('turnHighlightOff') :
-          loadTimeData.getString('turnHighlightOn');
-    }
   }
 
   // Loading the fonts stylesheet can take a while, especially with slow
@@ -445,12 +439,6 @@
 
     if (this.isReadAloudEnabled_) {
       this.speechRate_ = getCurrentSpeechRate();
-
-      if (!chrome.readingMode.isPhraseHighlightingEnabled) {
-        const highlightOn = chrome.readingMode.isHighlightOn();
-        this.setHighlightButtonTitle_(highlightOn);
-        this.setHighlightButtonIcon_(highlightOn);
-      }
     }
   }
 
@@ -547,29 +535,7 @@
   protected onHighlightClick_(event: MouseEvent) {
     // Click handler for the highlight button. Used both for the
     // highlight menu mode and the toggle button mode.
-    if (chrome.readingMode.isPhraseHighlightingEnabled) {
       this.$.highlightMenu.open(event.target as HTMLElement);
-    } else {
-      // Don't show the highlight menu if phrase highlighting is disabled.
-      this.onHighlightToggle_();
-    }
-  }
-
-  private onHighlightToggle_() {
-    assert(
-        !chrome.readingMode.isPhraseHighlightingEnabled,
-        'should not be called when highlighting menu is shown');
-    this.logger_.logSpeechSettingsChange(
-        ReadAloudSettingsChange.HIGHLIGHT_CHANGE);
-    const isHighlightOn = chrome.readingMode.isHighlightOn();
-    const turnOn = !isHighlightOn;
-    this.logger_.logHighlightState(turnOn);
-    this.setHighlightButtonIcon_(turnOn);
-    this.setHighlightButtonTitle_(turnOn);
-    this.fire(ToolbarEvent.HIGHLIGHT_CHANGE, {
-      data: turnOn ? chrome.readingMode.autoHighlighting :
-                     chrome.readingMode.noHighlighting,
-    });
   }
 
   private setHighlightButtonIcon_(turnOn: boolean) {
@@ -586,20 +552,6 @@
     }
   }
 
-  private setHighlightButtonTitle_(turnOn: boolean) {
-    // Sets the title of the highlight button. This is dynamically changed only
-    // when the highlight menu is disabled (i.e. the button acts as a toggle).
-    const button = this.$.toolbarContainer.querySelector('#highlight');
-    assert(button, 'no highlight button');
-    // The title is the opposite of the state, since it connotes the action that
-    // will be performed when the button is next clicked, and not the present
-    // state.
-    const title =
-        loadTimeData.getString(turnOn ? 'turnHighlightOff' : 'turnHighlightOn');
-    button.setAttribute('title', title);
-    button.setAttribute('aria-label', title);
-  }
-
   protected onFontClick_(e: Event) {
     this.logger_.logTextSettingsChange(ReadAnythingSettingsChange.FONT_CHANGE);
 
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index 6209e72..9e2b318b 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -260,6 +260,7 @@
       "//components/safe_browsing/content/browser:safe_browsing_blocking_page",
       "//components/safe_browsing/content/browser:safe_browsing_service",
       "//components/safe_browsing/content/browser/download:download_stats",
+      "//components/safe_browsing/content/browser/notification_content_detection:notifications_global_cache_list",
       "//components/safe_browsing/content/browser/password_protection",
       "//components/safe_browsing/content/browser/triggers",
       "//components/safe_browsing/content/browser/triggers:ad_sampler_trigger",
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 6813aba..a398e1e 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/test/with_feature_override.h"
 #include "build/build_config.h"
 #include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.h"
 #include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_factory.h"
@@ -1318,9 +1317,12 @@
   service_->SetIsAccountSignedIn(true);
 
   // Simulates change password.
-  EXPECT_CALL(*client_, UploadSecurityEventReport).Times(1);
+  base::RunLoop run_loop;
+  EXPECT_CALL(*client_, UploadSecurityEventReport)
+      .Times(1)
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
   service_->OnGaiaPasswordChanged("foo@example.com", false);
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 
 #if !BUILDFLAG(IS_ANDROID)
   ASSERT_EQ(1, test_event_router_->GetEventCount(
@@ -1355,14 +1357,17 @@
 
   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
                                     PASSWORD_REUSE);
-  EXPECT_CALL(*client_, UploadSecurityEventReport).Times(1);
+  base::RunLoop run_loop;
+  EXPECT_CALL(*client_, UploadSecurityEventReport)
+      .Times(1)
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
   NavigateAndCommit(GURL(kPasswordReuseURL));
   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
                  PasswordType::ENTERPRISE_PASSWORD,
                  /*is_warning_showing=*/false);
   SimulateRequestFinished(LoginReputationClientResponse::SAFE,
                           RequestOutcome::PASSWORD_ALERT_MODE);
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 #if !BUILDFLAG(IS_ANDROID)
   ASSERT_EQ(1, test_event_router_->GetEventCount(
                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
@@ -1381,13 +1386,16 @@
 
   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
                                     PASSWORD_REUSE);
-  EXPECT_CALL(*client_, UploadSecurityEventReport).Times(1);
+  base::RunLoop run_loop;
+  EXPECT_CALL(*client_, UploadSecurityEventReport)
+      .Times(1)
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
   service_->MaybeStartProtectedPasswordEntryRequest(
       web_contents(),
       /*main_frame_url=*/GURL("chrome-extension://some-fab-extension"),
       /*username=*/"enterprise_user", PasswordType::ENTERPRISE_PASSWORD,
       /*matching_reused_credentials=*/{}, /*password_field_exists=*/false);
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 #if !BUILDFLAG(IS_ANDROID)
   ASSERT_EQ(1, test_event_router_->GetEventCount(
                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
@@ -1535,12 +1543,15 @@
   PrepareRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
                  PasswordType::SAVED_PASSWORD,
                  /*is_warning_showing=*/false);
-  EXPECT_CALL(*client_, UploadSecurityEventReport).Times(1);
+  base::RunLoop run_loop;
+  EXPECT_CALL(*client_, UploadSecurityEventReport)
+      .Times(1)
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
   service_->MaybeReportPasswordReuseDetected(
       request_->main_frame_url(), kUserName, PasswordType::ENTERPRISE_PASSWORD,
       /*is_phishing_url =*/true,
       /*warning_shown =*/true);
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 #if !BUILDFLAG(IS_ANDROID)
   EXPECT_EQ(1, test_event_router_->GetEventCount(
                    OnPolicySpecifiedPasswordReuseDetected::kEventName));
@@ -1885,13 +1896,10 @@
   raw_ptr<syncer::TestSyncService> sync_service_ = nullptr;
 };
 
-class PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest
-    : public base::test::WithFeatureOverride,
-      public PasswordCheckupWithPhishGuardTest {
+class PasswordCheckupWithPhishGuardAndroidTest
+    : public PasswordCheckupWithPhishGuardTest {
  public:
-  PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest()
-      : base::test::WithFeatureOverride(
-            password_manager::features::kLoginDbDeprecationAndroid) {}
+  PasswordCheckupWithPhishGuardAndroidTest() = default;
 
   void SetUp() override {
     // Override the GMS version to be big enough for local UPM support, so these
@@ -1902,7 +1910,7 @@
   }
 };
 
-TEST_P(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
+TEST_F(PasswordCheckupWithPhishGuardAndroidTest,
        VerifyPhishGuardDialogOpensPasswordCheckupForAccountStoreSyncing) {
   service_->ConfigService(/*is_incognito=*/false,
                           /*is_extended_reporting=*/true);
@@ -1924,7 +1932,7 @@
   SimulateChangePasswordDialogAction(/*is_syncing=*/true);
 }
 
-TEST_P(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
+TEST_F(PasswordCheckupWithPhishGuardAndroidTest,
        VerifyPhishGuardDialogOpensPasswordCheckupForProfileStoreSyncing) {
   service_->ConfigService(/*is_incognito=*/false,
                           /*is_extended_reporting=*/true);
@@ -1947,7 +1955,7 @@
   SimulateChangePasswordDialogAction(/*is_syncing=*/true);
 }
 
-TEST_P(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
+TEST_F(PasswordCheckupWithPhishGuardAndroidTest,
        VerifyPhishGuardDialogOpensPasswordCheckupForProfileStoreNotSyncing) {
   service_->ConfigService(/*is_incognito=*/false,
                           /*is_extended_reporting=*/true);
@@ -1970,7 +1978,7 @@
   SimulateChangePasswordDialogAction(/*is_syncing=*/false);
 }
 
-TEST_P(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
+TEST_F(PasswordCheckupWithPhishGuardAndroidTest,
        VerifyPhishGuardDialogOpensSafetyCheckMenuForBothStoresSyncing) {
   feature_list_.InitWithFeatures(
       {}, {/*disabled_features=*/features::kSafetyHubLocalPasswordsModule});
@@ -1995,7 +2003,7 @@
   SimulateChangePasswordDialogAction(/*is_syncing=*/true);
 }
 
-TEST_P(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
+TEST_F(PasswordCheckupWithPhishGuardAndroidTest,
        VerifyPhishGuardDialogOpensSafetyHubMenuForBothStoresSyncing) {
   feature_list_.InitWithFeatures(
       /*enabled_features=*/{features::kSafetyHubLocalPasswordsModule}, {});
@@ -2020,70 +2028,6 @@
   SimulateChangePasswordDialogAction(/*is_syncing=*/true);
 }
 
-INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(
-    PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest);
-
-class PasswordCheckupWithPhishGuardUPMBeforeStoreSplitAndroidTest
-    : public PasswordCheckupWithPhishGuardTest {
- public:
-  void SetUp() override {
-    // Force split stores to be off by faking an outdated GmsCore version.
-    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test("0");
-    PasswordCheckupWithPhishGuardTest::SetUp();
-    feature_list_.InitAndDisableFeature(
-        password_manager::features::kLoginDbDeprecationAndroid);
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_F(
-    PasswordCheckupWithPhishGuardUPMBeforeStoreSplitAndroidTest,
-    VerifyPhishGuardDialogOpensPasswordCheckupEmptyAccountForNonSyncingUser) {
-  service_->ConfigService(/*is_incognito=*/false,
-                          /*is_extended_reporting=*/true);
-  std::vector<password_manager::MatchingReusedCredential> credentials;
-  credentials.emplace_back(
-      "http://example.test", GURL("http://example.test/"), u"user",
-      password_manager::PasswordForm::Store::kProfileStore);
-  service_->set_saved_passwords_matching_reused_credentials(credentials);
-
-  SetUpSyncService(/*is_syncing_passwords=*/false);
-
-  EXPECT_CALL(
-      *mock_checkup_launcher_,
-      LaunchCheckupOnDevice(
-          _, profile(), web_contents()->GetTopLevelNativeWindow(),
-          password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
-          /*account=*/""));
-
-  SimulateChangePasswordDialogAction(/*is_syncing=*/false);
-}
-
-TEST_F(PasswordCheckupWithPhishGuardUPMBeforeStoreSplitAndroidTest,
-       VerifyPhishGuardDialogOpensPasswordCheckupWithAnAccountForSyncingUser) {
-  service_->ConfigService(/*is_incognito=*/false,
-                          /*is_extended_reporting=*/true);
-  std::vector<password_manager::MatchingReusedCredential> credentials;
-  credentials.emplace_back(
-      "http://example.test", GURL("http://example.test/"), u"user",
-      password_manager::PasswordForm::Store::kProfileStore);
-
-  service_->set_saved_passwords_matching_reused_credentials(credentials);
-
-  SetUpSyncService(/*is_syncing_passwords=*/true);
-
-  EXPECT_CALL(
-      *mock_checkup_launcher_,
-      LaunchCheckupOnDevice(
-          _, profile(), web_contents()->GetTopLevelNativeWindow(),
-          password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
-          TestingProfile::kDefaultProfileUserName));
-
-  SimulateChangePasswordDialogAction(/*is_syncing=*/true);
-}
-
 #endif
 
 }  // namespace
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc b/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
index b7cad56..4903f728 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
@@ -2,11 +2,7 @@
 // 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 "base/compiler_specific.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
@@ -114,8 +110,8 @@
   base::ReadOnlySharedMemoryRegion GetModelSharedMemoryRegion() override {
     base::MappedReadOnlyRegion mapped_region =
         base::ReadOnlySharedMemoryRegion::Create(client_side_model_.length());
-    memcpy(mapped_region.mapping.memory(), client_side_model_.data(),
-           client_side_model_.length());
+    UNSAFE_TODO(memcpy(mapped_region.mapping.memory(),
+                       client_side_model_.data(), client_side_model_.length()));
     return mapped_region.region.Duplicate();
   }
 
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/connector_data_pipe_getter_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/connector_data_pipe_getter_unittest.cc
index 667838c..59db3f11 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/connector_data_pipe_getter_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/connector_data_pipe_getter_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 "chrome/browser/safe_browsing/cloud_content_scanning/connector_data_pipe_getter.h"
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/read_only_shared_memory_region.h"
@@ -71,7 +67,8 @@
     if (!region.IsValid())
       return base::ReadOnlySharedMemoryRegion();
 
-    std::memcpy(region.mapping.memory(), content.data(), content.size());
+    UNSAFE_TODO(
+        std::memcpy(region.mapping.memory(), content.data(), content.size()));
     return std::move(region.region);
   }
 
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/resumable_uploader_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/resumable_uploader_unittest.cc
index 590eee5a..3942e4a 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/resumable_uploader_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/resumable_uploader_unittest.cc
@@ -1,16 +1,12 @@
 // Copyright 2024 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-#include "base/base64.h"
-#include "components/enterprise/common/proto/connectors.pb.h"
-#include "net/http/http_status_code.h"
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
+#include "chrome/browser/safe_browsing/cloud_content_scanning/resumable_uploader.h"
 
 #include <memory>
 
+#include "base/base64.h"
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
@@ -25,9 +21,10 @@
 #include "chrome/browser/enterprise/connectors/test/uploader_test_utils.h"
 #include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
 #include "chrome/browser/safe_browsing/cloud_content_scanning/connector_upload_request.h"
-#include "chrome/browser/safe_browsing/cloud_content_scanning/resumable_uploader.h"
+#include "components/enterprise/common/proto/connectors.pb.h"
 #include "content/public/test/browser_task_environment.h"
 #include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
@@ -106,7 +103,8 @@
     base::MappedReadOnlyRegion region =
         base::ReadOnlySharedMemoryRegion::Create(content.size());
     EXPECT_TRUE(region.IsValid());
-    std::memcpy(region.mapping.memory(), content.data(), content.size());
+    UNSAFE_TODO(
+        std::memcpy(region.mapping.memory(), content.data(), content.size()));
     return std::move(region.region);
   }
 
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
index b6f07a40..b3980fb 100644
--- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request_unittest.cc
@@ -788,7 +788,13 @@
   MetadataSourceType GetMetadataSourceType() { return GetParam(); }
 };
 
-TEST_P(DeepScanningReportingSourceTypeTest, ProcessesResponseCorrectly) {
+// TODO(crbug.com/433865922): Disable this test on Windows because of flakiness.
+#if BUILDFLAG(IS_WIN)
+  #define MAYBE_ProcessesResponseCorrectly DISABLED_ProcessesResponseCorrectly
+#else
+  #define MAYBE_ProcessesResponseCorrectly ProcessesResponseCorrectly
+#endif
+TEST_P(DeepScanningReportingSourceTypeTest, MAYBE_ProcessesResponseCorrectly) {
   {
     base::RunLoop run_loop;
     DeepScanningRequest request(
diff --git a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.cc b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.cc
index 963ba29..28efde1 100644
--- a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.cc
+++ b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/push_messaging/push_messaging_service_factory.h"
 #include "chrome/browser/push_messaging/push_messaging_service_impl.h"
 #include "chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory.h"
+#include "components/safe_browsing/content/browser/notification_content_detection/notifications_global_cache_list.h"
 #include "components/safe_browsing/core/browser/db/database_manager.h"
 #include "components/safe_browsing/core/common/proto/csd.pb.h"
 #include "components/safe_browsing/core/common/utils.h"
@@ -155,9 +156,18 @@
     service_worker_info.scope = scope;
     service_worker_info.registration_id = registration_id;
     service_worker_info.resources = service_worker_registration_info.resources;
-    database_manager_->CheckUrlForHighConfidenceAllowlist(
-        scope, base::BindOnce(&NotificationTelemetryService::DatabaseCheckDone,
-                              weak_factory_.GetWeakPtr(), service_worker_info));
+
+    // TODO(crbug.com/433543634): Clean up the use of `database_manager_` post
+    // GlobalCacheListForGatingNotificationProtections launch.
+    if (database_manager_ == nullptr) {
+      MaybeStoreServiceWorkerInfo(
+          service_worker_info, IsDomainInNotificationsGlobalCacheList(scope));
+    } else {
+      database_manager_->CheckUrlForHighConfidenceAllowlist(
+          scope,
+          base::BindOnce(&NotificationTelemetryService::DatabaseCheckDone,
+                         weak_factory_.GetWeakPtr(), service_worker_info));
+    }
   }
 }
 
@@ -172,6 +182,12 @@
     std::optional<
         SafeBrowsingDatabaseManager::HighConfidenceAllowlistCheckLoggingDetails>
         logging_details) {
+  MaybeStoreServiceWorkerInfo(service_worker_info, allow_listed);
+}
+
+void NotificationTelemetryService::MaybeStoreServiceWorkerInfo(
+    ServiceWorkerTelemetryInfo service_worker_info,
+    bool allow_listed) {
   base::UmaHistogramBoolean(
       "SafeBrowsing.NotificationTelemetry.ServiceWorkerScopeURL.IsAllowlisted",
       allow_listed);
diff --git a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.h b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.h
index 93ab8e39..5ba53f0c 100644
--- a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.h
+++ b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.h
@@ -79,6 +79,14 @@
                            SendsTelemetryReport);
   FRIEND_TEST_ALL_PREFIXES(NotificationTelemetryServiceTest,
                            EnforcesServiceWorkerInfoCacheSize);
+  // TODO(crbug.com/433543634): Clean up post
+  // GlobalCacheListForGatingNotificationProtections launch.
+  FRIEND_TEST_ALL_PREFIXES(
+      NotificationTelemetryServiceFactoryTest,
+      CreatedWithoutDatabaseManagerWhenGlobalCacheListEnabled);
+  FRIEND_TEST_ALL_PREFIXES(
+      NotificationTelemetryServiceFactoryTest,
+      CreatedWithDatabaseManagerWhenGlobalCacheListDisabled);
 
   // Callback used for checking the Safe Browsing allowlist.
   void DatabaseCheckDone(
@@ -88,6 +96,11 @@
                         HighConfidenceAllowlistCheckLoggingDetails>
           logging_details);
 
+  // Store the service work info if the scope URL is not allowlisted.
+  void MaybeStoreServiceWorkerInfo(
+      ServiceWorkerTelemetryInfo service_worker_info,
+      bool allowlisted);
+
   // Used for logging after an upload.
   void UploadComplete(std::unique_ptr<std::string> response_body);
 
@@ -105,6 +118,8 @@
   // Accessor for an URLLoaderFactory with which reports will be sent.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
+  // TODO(crbug.com/433543634): Remove `database_manager_` post
+  // GlobalCacheListForGatingNotificationProtections launch.
   // Used to preform the Safe Browsing allowlist lookup.
   scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
 
diff --git a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory.cc b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory.cc
index 4fa76897..34f4d9c2 100644
--- a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory.cc
+++ b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory.cc
@@ -46,15 +46,28 @@
 // The ClientIncidentReport proto used to send these reports increases the
 // Android binary size by more than the arm32 threshold.
 #if !BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64))
-  if (!g_browser_process || !g_browser_process->safe_browsing_service() ||
-      !g_browser_process->safe_browsing_service()->database_manager()) {
+  if (!g_browser_process) {
     return nullptr;
   }
 
-  return std::make_unique<NotificationTelemetryService>(
-      Profile::FromBrowserContext(context),
-      g_browser_process->shared_url_loader_factory(),
-      g_browser_process->safe_browsing_service()->database_manager());
+  if (base::FeatureList::IsEnabled(
+          kGlobalCacheListForGatingNotificationProtections)) {
+    return std::make_unique<NotificationTelemetryService>(
+        Profile::FromBrowserContext(context),
+        g_browser_process->shared_url_loader_factory(), nullptr);
+  } else {
+    // TODO(crbug.com/433543634): Clean up the use of `database_manager` post
+    // GlobalCacheListForGatingNotificationProtections launch.
+    if (!g_browser_process->safe_browsing_service() ||
+        !g_browser_process->safe_browsing_service()->database_manager()) {
+      return nullptr;
+    }
+    return std::make_unique<NotificationTelemetryService>(
+        Profile::FromBrowserContext(context),
+        g_browser_process->shared_url_loader_factory(),
+        g_browser_process->safe_browsing_service()->database_manager());
+  }
+
 #else
   return nullptr;
 #endif  // !(!BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_ANDROID) &&
diff --git a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory_unittest.cc b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory_unittest.cc
index a34bddf3..c9c721a3 100644
--- a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory_unittest.cc
+++ b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_factory_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/system/sys_info.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
+#include "chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
@@ -42,6 +43,7 @@
  protected:
   content::BrowserTaskEnvironment task_environment_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
  private:
   scoped_refptr<safe_browsing::SafeBrowsingService> sb_service_;
@@ -77,4 +79,40 @@
             NotificationTelemetryServiceFactory::GetForProfile(profile));
 }
 
+TEST_F(NotificationTelemetryServiceFactoryTest,
+       CreatedWithDatabaseManagerWhenGlobalCacheListDisabled) {
+  scoped_feature_list_.InitAndDisableFeature(
+      kGlobalCacheListForGatingNotificationProtections);
+  TestingProfile* profile =
+      profile_manager_->CreateTestingProfile("testing_profile");
+  NotificationTelemetryService* notification_telemetry_service =
+      NotificationTelemetryServiceFactory::GetForProfile(profile);
+#if !BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64))
+  EXPECT_NE(nullptr, notification_telemetry_service);
+  EXPECT_NE(nullptr, notification_telemetry_service->database_manager_);
+#else
+  // Service is not created for Android arm32 devices.
+  EXPECT_EQ(nullptr, notification_telemetry_service);
+#endif  // !(!BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_ANDROID) &&
+        // defined(ARCH_CPU_ARM64)))
+}
+
+TEST_F(NotificationTelemetryServiceFactoryTest,
+       CreatedWithoutDatabaseManagerWhenGlobalCacheListEnabled) {
+  scoped_feature_list_.InitAndEnableFeature(
+      kGlobalCacheListForGatingNotificationProtections);
+  TestingProfile* profile =
+      profile_manager_->CreateTestingProfile("testing_profile");
+  NotificationTelemetryService* notification_telemetry_service =
+      NotificationTelemetryServiceFactory::GetForProfile(profile);
+#if !BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64))
+  EXPECT_NE(nullptr, notification_telemetry_service);
+  EXPECT_EQ(nullptr, notification_telemetry_service->database_manager_);
+#else
+  // Service is not created for Android arm32 devices.
+  EXPECT_EQ(nullptr, notification_telemetry_service);
+#endif  // !(!BUILDFLAG(IS_ANDROID) || (BUILDFLAG(IS_ANDROID) &&
+        // defined(ARCH_CPU_ARM64)))
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_unittest.cc b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_unittest.cc
index 9731e81..f8ea501f 100644
--- a/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_unittest.cc
+++ b/chrome/browser/safe_browsing/notification_telemetry/notification_telemetry_service_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/safe_browsing/content/browser/notification_content_detection/mock_safe_browsing_database_manager.h"
+#include "components/safe_browsing/content/browser/notification_content_detection/notifications_global_cache_list.h"
 #include "components/safe_browsing/core/common/features.h"
 #include "components/safe_browsing/core/common/proto/csd.pb.h"
 #include "content/public/browser/service_worker_registration_information.h"
@@ -34,18 +35,31 @@
 const char kSbIncidentReportUrl[] =
     "https://sb-ssl.google.com/safebrowsing/clientreport/incident";
 
-class NotificationTelemetryServiceTest : public ::testing::Test {
+class NotificationTelemetryServiceTest : public ::testing::TestWithParam<bool> {
  public:
   NotificationTelemetryServiceTest() = default;
 
+  bool IsGlobalCacheListFeatureEnabled() { return GetParam(); }
+
   void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(kNotificationTelemetry);
-    database_manager_ = new MockSafeBrowsingDatabaseManager();
     profile_.GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnhanced, true);
-    notification_telemetry_service_ =
-        std::make_unique<NotificationTelemetryService>(
-            &profile_, test_url_loader_factory_.GetSafeWeakWrapper(),
-            database_manager_);
+
+    if (IsGlobalCacheListFeatureEnabled()) {
+      notification_telemetry_service_ =
+          std::make_unique<NotificationTelemetryService>(
+              &profile_, test_url_loader_factory_.GetSafeWeakWrapper(),
+              nullptr);
+
+    } else {
+      // TODO(crbug.com/433543634): Cleanup the use of `database_manager_` post
+      // GlobalCacheListForGatingNotificationProtections launch.
+      database_manager_ = new MockSafeBrowsingDatabaseManager();
+      notification_telemetry_service_ =
+          std::make_unique<NotificationTelemetryService>(
+              &profile_, test_url_loader_factory_.GetSafeWeakWrapper(),
+              database_manager_);
+    }
   }
 
   void TearDown() override { notification_telemetry_service_.reset(); }
@@ -54,6 +68,14 @@
     return database_manager_;
   }
 
+  void SetAllowlistInfoForUrl(const GURL& scope, bool allowlisted) {
+    if (IsGlobalCacheListFeatureEnabled() && allowlisted) {
+      SetNotificationsGlobalCacheListDomainsForTesting({scope.host()});
+    } else if (!IsGlobalCacheListFeatureEnabled()) {
+      database_manager()->SetAllowlistLookupDetailsForUrl(scope, allowlisted);
+    }
+  }
+
   base::HistogramTester& histogram_tester() { return histogram_tester_; }
 
   std::unique_ptr<NotificationTelemetryService> notification_telemetry_service_;
@@ -67,11 +89,11 @@
   base::HistogramTester histogram_tester_;
 };
 
-TEST_F(NotificationTelemetryServiceTest, Initializes) {
+TEST_P(NotificationTelemetryServiceTest, Initializes) {
   ASSERT_NE(notification_telemetry_service_.get(), nullptr);
 }
 
-TEST_F(NotificationTelemetryServiceTest, SendsTelemetryReport) {
+TEST_P(NotificationTelemetryServiceTest, SendsTelemetryReport) {
   const GURL scope("https://nonallowlisted_url.com/");
   const GURL scope2("https://allowlisted_url.com/");
   const GURL scope3("https://nonallowlisted_url_2.com/");
@@ -95,13 +117,13 @@
   content::ServiceWorkerRegistrationInformation service_worker_info_3;
   service_worker_info_3.resources.push_back(scope3);
 
-  database_manager()->SetAllowlistLookupDetailsForUrl(scope2, /*match=*/true);
+  SetAllowlistInfoForUrl(scope2, /*allowlisted=*/true);
   notification_telemetry_service_->OnRegistrationStored(
       registration_id_2, scope2, service_worker_info_2);
-  database_manager()->SetAllowlistLookupDetailsForUrl(scope, /*match=*/false);
+  SetAllowlistInfoForUrl(scope, /*allowlisted=*/false);
   notification_telemetry_service_->OnRegistrationStored(
       registration_id_1, scope, service_worker_info_1);
-  database_manager()->SetAllowlistLookupDetailsForUrl(scope3, /*match=*/false);
+  SetAllowlistInfoForUrl(scope3, /*allowlisted=*/false);
   notification_telemetry_service_->OnRegistrationStored(
       registration_id_3, scope3, service_worker_info_3);
 
@@ -136,7 +158,7 @@
       /*expected_bucket_count=*/1);
 }
 
-TEST_F(NotificationTelemetryServiceTest, EnforcesServiceWorkerInfoCacheSize) {
+TEST_P(NotificationTelemetryServiceTest, EnforcesServiceWorkerInfoCacheSize) {
   const GURL scope("https://nonallowlisted_url.com/");
   const GURL scope2("https://nonallowlisted_url_2.com/");
   const GURL import_URL("https://import_script.com/script.js");
@@ -148,12 +170,12 @@
   content::ServiceWorkerRegistrationInformation service_worker_info_1;
   service_worker_info_1.resources.push_back(import_URL);
 
-  database_manager()->SetAllowlistLookupDetailsForUrl(scope, /*match=*/false);
+  SetAllowlistInfoForUrl(scope, /*allowlisted=*/false);
   notification_telemetry_service_->OnRegistrationStored(
       registration_id_1, scope, service_worker_info_1);
 
   // Second valid service worker info
-  database_manager()->SetAllowlistLookupDetailsForUrl(scope2, /*match=*/false);
+  SetAllowlistInfoForUrl(scope2, /*allowlisted=*/false);
   content::ServiceWorkerRegistrationInformation service_worker_info_2;
   service_worker_info_2.resources.push_back(import_URL);
 
@@ -174,4 +196,8 @@
   EXPECT_EQ(0, test_url_loader_factory_.NumPending());
 }
 
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         NotificationTelemetryServiceTest,
+                         ::testing::Bool());
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index f9efef7a..78afabf 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
 #include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
 #include "chrome/browser/profiles/profile.h"
@@ -391,6 +392,10 @@
   raw_ptr<const BrowserList> active_browser_list_ = nullptr;
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 #if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
   base::test::ScopedFeatureList scoped_feature_list_;
 #endif  // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
diff --git a/chrome/browser/share/editor_screenshot_task.cc b/chrome/browser/share/editor_screenshot_task.cc
index ef407fa..02f5e7d 100644
--- a/chrome/browser/share/editor_screenshot_task.cc
+++ b/chrome/browser/share/editor_screenshot_task.cc
@@ -34,7 +34,8 @@
     scoped_refptr<base::RefCountedMemory> png_data) {
   if (png_data.get()) {
     size_t size = png_data->size();
-    ScopedJavaLocalRef<jbyteArray> jbytes(env, env->NewByteArray(size));
+    auto jbytes =
+        ScopedJavaLocalRef<jbyteArray>::Adopt(env, env->NewByteArray(size));
     env->SetByteArrayRegion(jbytes.obj(), 0, size, (jbyte*)png_data->front());
     Java_EditorScreenshotTask_onBytesReceived(env, callback, jbytes);
   } else {
diff --git a/chrome/browser/shutdown_signal_handlers_posix.cc b/chrome/browser/shutdown_signal_handlers_posix.cc
index 21de219..65168ff 100644
--- a/chrome/browser/shutdown_signal_handlers_posix.cc
+++ b/chrome/browser/shutdown_signal_handlers_posix.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/shutdown_signal_handlers_posix.h"
 
 #include <limits.h>
@@ -16,6 +11,7 @@
 
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/debug/leak_annotations.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
@@ -39,7 +35,7 @@
 void GracefulShutdownHandler(int signal) {
   // Reinstall the default handler.  We had one shot at graceful shutdown.
   struct sigaction action;
-  memset(&action, 0, sizeof(action));
+  UNSAFE_TODO(memset(&action, 0, sizeof(action)));
   action.sa_handler = SIG_DFL;
   RAW_CHECK(sigaction(signal, &action, nullptr) == 0);
 
@@ -49,10 +45,10 @@
   RAW_CHECK(g_pipe_pid == getpid());
   size_t bytes_written = 0;
   do {
-    int rv = HANDLE_EINTR(
+    int rv = UNSAFE_TODO(HANDLE_EINTR(
         write(g_shutdown_pipe_write_fd,
               reinterpret_cast<const char*>(&signal) + bytes_written,
-              sizeof(signal) - bytes_written));
+              sizeof(signal) - bytes_written)));
     RAW_CHECK(rv >= 0);
     bytes_written += rv;
   } while (bytes_written < sizeof(signal));
@@ -123,9 +119,9 @@
   size_t bytes_read = 0;
   ssize_t ret;
   do {
-    ret = HANDLE_EINTR(read(shutdown_fd_,
-                            reinterpret_cast<char*>(&signal) + bytes_read,
-                            sizeof(signal) - bytes_read));
+    ret = UNSAFE_TODO(HANDLE_EINTR(
+        read(shutdown_fd_, reinterpret_cast<char*>(&signal) + bytes_read,
+             sizeof(signal) - bytes_read)));
     if (ret < 0) {
       NOTREACHED() << "Unexpected error: " << strerror(errno);
     } else if (ret == 0) {
@@ -191,7 +187,7 @@
   // We need to handle SIGTERM, because that is how many POSIX-based distros
   // ask processes to quit gracefully at shutdown time.
   struct sigaction action;
-  memset(&action, 0, sizeof(action));
+  UNSAFE_TODO(memset(&action, 0, sizeof(action)));
   action.sa_handler = SIGTERMHandler;
   CHECK_EQ(0, sigaction(SIGTERM, &action, nullptr));
 
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc
index 0108674..2419ff7 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.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 "chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.h"
 
 #include <string_view>
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
index 8796656..20cf017 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -735,11 +735,10 @@
   EXPECT_TRUE(IsChromeSignedIn());
 
   // Check that the password account storage is enabled.
-  PrefService* pref_service = GetProfile()->GetPrefs();
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
-  EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   CheckHistograms(histogram_tester,
                   SigninInterceptionHeuristicOutcome::kInterceptChromeSignin);
@@ -791,7 +790,6 @@
 
   EXPECT_FALSE(IsChromeSignedIn());
   EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile()->GetPrefs(),
       SyncServiceFactory::GetForProfile(GetProfile())));
 
   CheckHistograms(histogram_tester,
@@ -1143,25 +1141,24 @@
                                         SigninInterceptionResult::kAccepted);
 
   // Check that the password account storage is enabled.
-  PrefService* pref_service = GetProfile()->GetPrefs();
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
-  EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   // Disable account storage.
   sync_service->GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, false);
 
   // Check that the password account storage is disabled.
-  EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   Signout();
 
   // Check that the password account storage is false if there is no account.
-  EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   // Log in again.
   // Force a Chrome Signin. The bubble will not be shown again.
@@ -1169,8 +1166,8 @@
       email, signin::ConsentLevel::kSignin);
 
   // Check that the password account storage is still disabled.
-  EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 }
 
 // Test the recording of the user entering or resolving an inconsistent state
@@ -1504,7 +1501,6 @@
       prefs::kExplicitBrowserSignin));
   // Passwords are defaulted to disabled without an explicit signin.
   EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile()->GetPrefs(),
       SyncServiceFactory::GetForProfile(GetProfile())));
 
   SetSignoutAllowed(false);
@@ -1524,11 +1520,10 @@
       prefs::kExplicitBrowserSignin));
   // Since we did not interact with passwords before, passwords should remain
   // disabled as long as we did not explicitly sign in.
-  PrefService* pref_service = GetProfile()->GetPrefs();
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
-  EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   // Sign out, and sign back in.
   SetSignoutAllowed(true);
@@ -1547,8 +1542,8 @@
       prefs::kExplicitBrowserSignin));
   // Signing in with explicit signin enabled, should affect the passwords
   // default.
-  EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  EXPECT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 
   // Sign out should clear the explicit signin pref.
   identity_test_env()->ClearPrimaryAccount();
diff --git a/chrome/browser/site_isolation/origin_agent_cluster_browsertest.cc b/chrome/browser/site_isolation/origin_agent_cluster_browsertest.cc
index a7dc79cb..7f26fa6 100644
--- a/chrome/browser/site_isolation/origin_agent_cluster_browsertest.cc
+++ b/chrome/browser/site_isolation/origin_agent_cluster_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/metrics/metrics_memory_details.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -177,6 +178,10 @@
     return nullptr;
   }
 
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   net::EmbeddedTestServer https_server_;
   base::test::ScopedFeatureList feature_list_;
   bool enable_origin_agent_cluster_;
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
index 9a0170e..3c74fee9 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.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 "chrome/browser/spellchecker/spellcheck_custom_dictionary.h"
 
 #include <stddef.h>
diff --git a/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc b/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
index 1aa5e9b0..9f4cf4ec 100644
--- a/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
+++ b/chrome/browser/ssl/typed_navigation_upgrade_throttle_browsertest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_test_utils.h"
 #include "chrome/browser/interstitials/security_interstitial_page_test_utils.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ssl/https_upgrades_interceptor.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -449,6 +450,10 @@
                                  error_page::NETWORK_ERROR_PAGE_SHOWN, 0);
   }
 
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
 
diff --git a/chrome/browser/support_tool/screenshot_data_collector_unittest.cc b/chrome/browser/support_tool/screenshot_data_collector_unittest.cc
index b7464f8..1dfdbd2 100644
--- a/chrome/browser/support_tool/screenshot_data_collector_unittest.cc
+++ b/chrome/browser/support_tool/screenshot_data_collector_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 "chrome/browser/support_tool/screenshot_data_collector.h"
 
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted_memory.h"
@@ -63,8 +59,8 @@
 
     webrtc::DesktopSize size(bitmap_.width(), bitmap_.height());
     frame_ = std::make_unique<webrtc::BasicDesktopFrame>(std::move(size));
-    std::memcpy(frame_->data(), bitmap_.getAddr32(0, 0),
-                bitmap_.rowBytes() * bitmap_.height());
+    UNSAFE_TODO(std::memcpy(frame_->data(), bitmap_.getAddr32(0, 0),
+                            bitmap_.rowBytes() * bitmap_.height()));
     jpeg_data_ = base::MakeRefCounted<base::RefCountedString>(std::move(data));
 
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index b1c2309..767b0d80 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -32,11 +32,6 @@
 #include "components/trusted_vault/trusted_vault_service.h"
 #include "content/public/browser/browser_thread.h"
 
-#if BUILDFLAG(IS_ANDROID)
-#include "components/keyed_service/core/service_access_type.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#endif  // BUILDFLAG(IS_ANDROID)
-
 namespace browser_sync {
 namespace {
 
@@ -158,36 +153,6 @@
   return true;
 }
 
-bool ChromeSyncClient::IsPasswordSyncAllowed() {
-#if BUILDFLAG(IS_ANDROID)
-  return pref_service_->GetInteger(
-             password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores) !=
-             static_cast<int>(
-                 password_manager::prefs::UseUpmLocalAndSeparateStoresState::
-                     kOffAndMigrationPending) ||
-         base::FeatureList::IsEnabled(
-             password_manager::features::kLoginDbDeprecationAndroid);
-#else
-  return true;
-#endif  // BUILDFLAG(IS_ANDROID)
-}
-
-void ChromeSyncClient::SetPasswordSyncAllowedChangeCb(
-    const base::RepeatingClosure& cb) {
-#if BUILDFLAG(IS_ANDROID)
-  CHECK(!upm_pref_change_registrar_.prefs())
-      << "SetPasswordSyncAllowedChangeCb() must be called at most once";
-  upm_pref_change_registrar_.Init(pref_service_);
-  // This overfires: the kPasswordsUseUPMLocalAndSeparateStores pref might have
-  // changed value, but not IsPasswordSyncAllowed(). That's fine, `cb` should
-  // handle this case.
-  upm_pref_change_registrar_.Add(
-      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores, cb);
-#else
-  // IsPasswordSyncAllowed() doesn't change outside of Android.
-#endif  // BUILDFLAG(IS_ANDROID)
-}
-
 void ChromeSyncClient::RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial(
     const syncer::TrustedVaultAutoUpgradeSyntheticFieldTrialGroup& group) {
   CHECK(group.is_valid());
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index 38b2c8af..889db708 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -10,7 +10,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/raw_ptr.h"
 #include "components/browser_sync/sync_engine_factory_impl.h"
-#include "components/prefs/pref_change_registrar.h"
 #include "components/sync/service/sync_client.h"
 #include "extensions/buildflags/buildflags.h"
 
@@ -59,9 +58,6 @@
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
   syncer::SyncEngineFactory* GetSyncEngineFactory() override;
   bool IsCustomPassphraseAllowed() override;
-  bool IsPasswordSyncAllowed() override;
-  void SetPasswordSyncAllowedChangeCb(
-      const base::RepeatingClosure& cb) override;
   void RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial(
       const syncer::TrustedVaultAutoUpgradeSyntheticFieldTrialGroup& group)
       override;
@@ -76,11 +72,6 @@
       supervised_user_settings_service_;
   const std::unique_ptr<ExtensionsActivityMonitor> extensions_activity_monitor_;
   SyncEngineFactoryImpl engine_factory_;
-
-#if BUILDFLAG(IS_ANDROID)
-  // Watches password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores.
-  PrefChangeRegistrar upm_pref_change_registrar_;
-#endif  // BUILDFLAG(IS_ANDROID)
 };
 
 }  // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc
index 5d61540..ce5d3a82 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.cc
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.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 "chrome/browser/sync/test/integration/bookmarks_helper.h"
 
 #include <stddef.h>
@@ -18,6 +13,7 @@
 #include <set>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/stack.h"
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
@@ -256,8 +252,8 @@
   EXPECT_TRUE(node_pixel_addr_a);
   void* node_pixel_addr_b = bitmap_b.getPixels();
   EXPECT_TRUE(node_pixel_addr_b);
-  if (memcmp(node_pixel_addr_a, node_pixel_addr_b,
-             bitmap_a.computeByteSize()) != 0) {
+  if (UNSAFE_TODO(memcmp(node_pixel_addr_a, node_pixel_addr_b,
+                         bitmap_a.computeByteSize())) != 0) {
     LOG(ERROR) << "Favicon bitmap mismatch";
     return false;
   } else {
diff --git a/chrome/browser/sync/test/integration/password_manager_sync_test.cc b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
index 6573c77..e97212a3 100644
--- a/chrome/browser/sync/test/integration/password_manager_sync_test.cc
+++ b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
@@ -886,11 +886,11 @@
 
   SignIn(SyncTestAccount::kConsumerAccount1, /*explicit_signin=*/false);
   EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
   SignOut();
   SignIn(SyncTestAccount::kConsumerAccount2, /*explicit_signin=*/false);
   EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest,
@@ -911,11 +911,11 @@
 
   SignIn(SyncTestAccount::kConsumerAccount1);
   EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
   SignOut();
   SignIn(SyncTestAccount::kConsumerAccount2);
   EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
 }
 
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
@@ -939,7 +939,7 @@
   ASSERT_EQ(fake_server_->GetSyncEntitiesByDataType(syncer::PASSWORDS).size(),
             1u);
   EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
 
   // Clear cookies and account passwords.
   content::BrowsingDataRemover* remover =
@@ -959,12 +959,12 @@
 
   // Account storage is still enabled (because the user is still signed in).
   EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
 
   // The preference is reset as the account is removed from Chrome.
   SignOut();
   EXPECT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
 }
 
 // TODO(b/327118794): Delete this test once implicit signin no longer exists.
@@ -1016,7 +1016,7 @@
 
   // Since we mangled the prefs file, account storage should be disabled.
   ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
   ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PASSWORDS));
 
   // The account-scoped store should have been cleared during startup, and the
diff --git a/chrome/browser/sync/test/integration/single_client_outgoing_password_sharing_invitation_test.cc b/chrome/browser/sync/test/integration/single_client_outgoing_password_sharing_invitation_test.cc
index 86f65ed..9ce5d86 100644
--- a/chrome/browser/sync/test/integration/single_client_outgoing_password_sharing_invitation_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_outgoing_password_sharing_invitation_test.cc
@@ -216,7 +216,7 @@
   ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
   ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
   ASSERT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      GetProfile(0)->GetPrefs(), GetSyncService(0)));
+      GetSyncService(0)));
 
   PasswordRecipient recipient = {
       .user_id = kRecipientUserId,
diff --git a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
index 405b237..418178f4 100644
--- a/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/leveldb_wrapper_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h"
 
 #include <stddef.h>
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index 32152b6..94ef2da 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
 
 #include <stdint.h>
diff --git a/chrome/browser/sync_file_system/file_change_unittest.cc b/chrome/browser/sync_file_system/file_change_unittest.cc
index 2926d8c..6958c23 100644
--- a/chrome/browser/sync_file_system/file_change_unittest.cc
+++ b/chrome/browser/sync_file_system/file_change_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/sync_file_system/file_change.h"
 
 #include <stddef.h>
 
+#include "base/compiler_specific.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace sync_file_system {
@@ -38,7 +34,7 @@
 void CreateList(FileChangeList* list, const FileChange (&inputs)[INPUT_SIZE]) {
   list->clear();
   for (size_t i = 0; i < INPUT_SIZE; ++i)
-    list->Update(inputs[i]);
+    list->Update(UNSAFE_TODO(inputs[i]));
 }
 
 template <size_t EXPECTED_SIZE>
@@ -47,10 +43,11 @@
   SCOPED_TRACE(testing::Message() << "actual:" << list.DebugString());
   ASSERT_EQ(EXPECTED_SIZE, list.size());
   for (size_t i = 0; i < list.size(); ++i) {
-    SCOPED_TRACE(testing::Message() << i << ": "
-                 << " expected:" << expected[i].DebugString()
-                 << " actual:" << list.list().at(i).DebugString());
-    EXPECT_EQ(expected[i], list.list().at(i));
+    UNSAFE_TODO(SCOPED_TRACE(testing::Message()
+                             << i << ": "
+                             << " expected:" << expected[i].DebugString()
+                             << " actual:" << list.list().at(i).DebugString()));
+    UNSAFE_TODO(EXPECT_EQ(expected[i], list.list().at(i)));
   }
 }
 
diff --git a/chrome/browser/tab/tab_state_storage_service.cc b/chrome/browser/tab/tab_state_storage_service.cc
index 7d824c0..aec1e4f 100644
--- a/chrome/browser/tab/tab_state_storage_service.cc
+++ b/chrome/browser/tab/tab_state_storage_service.cc
@@ -29,10 +29,11 @@
     std::string web_contents_state_bytes = tab_state.web_contents_state_bytes();
     std::string* heap_web_contents_state_bytes =
         new std::string(web_contents_state_bytes);
-    base::android::ScopedJavaLocalRef<jobject> j_web_contents_state_buffer(
-        env, env->NewDirectByteBuffer(
-                 static_cast<void*>(heap_web_contents_state_bytes->data()),
-                 heap_web_contents_state_bytes->size()));
+    auto j_web_contents_state_buffer =
+        base::android::ScopedJavaLocalRef<jobject>::Adopt(
+            env, env->NewDirectByteBuffer(
+                     static_cast<void*>(heap_web_contents_state_bytes->data()),
+                     heap_web_contents_state_bytes->size()));
 
     base::Token tab_group_token(tab_state.tab_group_id_high(),
                                 tab_state.tab_group_id_low());
diff --git a/chrome/browser/tab/web_contents_state.cc b/chrome/browser/tab/web_contents_state.cc
index 4162c5f3..2146b652 100644
--- a/chrome/browser/tab/web_contents_state.cc
+++ b/chrome/browser/tab/web_contents_state.cc
@@ -76,7 +76,7 @@
   if (base::android::ClearException(env)) {
     return {};
   }
-  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+  return base::android::ScopedJavaLocalRef<jobject>::Adopt(env, ret);
 }
 
 void WriteStateHeaderToPickle(bool off_the_record,
diff --git a/chrome/browser/task_manager/providers/web_contents/background_contents_tag_browsertest.cc b/chrome/browser/task_manager/providers/web_contents/background_contents_tag_browsertest.cc
index ab82fbc..2b58bf05 100644
--- a/chrome/browser/task_manager/providers/web_contents/background_contents_tag_browsertest.cc
+++ b/chrome/browser/task_manager/providers/web_contents/background_contents_tag_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/background/background_contents_test_waiter.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/task_manager/mock_web_contents_task_manager.h"
 #include "chrome/browser/task_manager/providers/web_contents/web_contents_tags_manager.h"
@@ -63,6 +64,12 @@
     command_line->AppendSwitch(embedder_support::kDisablePopupBlocking);
     command_line->AppendSwitch(extensions::switches::kAllowHTTPBackgroundPage);
   }
+
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 // Tests that loading an extension that has a background contents will result in
diff --git a/chrome/browser/task_manager/providers/web_contents/devtools_tag_browsertest.cc b/chrome/browser/task_manager/providers/web_contents/devtools_tag_browsertest.cc
index a3403eb2..1782189 100644
--- a/chrome/browser/task_manager/providers/web_contents/devtools_tag_browsertest.cc
+++ b/chrome/browser/task_manager/providers/web_contents/devtools_tag_browsertest.cc
@@ -6,6 +6,7 @@
 #include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/task_manager/mock_web_contents_task_manager.h"
 #include "chrome/browser/task_manager/providers/web_contents/web_contents_tags_manager.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -58,6 +59,10 @@
   }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   raw_ptr<DevToolsWindow, AcrossTasksDanglingUntriaged> devtools_window_;
 };
 
diff --git a/chrome/browser/task_manager/providers/web_contents/subframe_task_browsertest.cc b/chrome/browser/task_manager/providers/web_contents/subframe_task_browsertest.cc
index b838a2a..e096349 100644
--- a/chrome/browser/task_manager/providers/web_contents/subframe_task_browsertest.cc
+++ b/chrome/browser/task_manager/providers/web_contents/subframe_task_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/task_manager/mock_web_contents_task_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -79,6 +80,12 @@
     ASSERT_TRUE(ui_test_utils::NavigateToURL(
         browser(), embedded_test_server()->GetURL(page_url)));
   }
+
+ private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
 };
 
 // Makes sure that, if sites are isolated, the task manager will show the
diff --git a/chrome/browser/themes/BUILD.gn b/chrome/browser/themes/BUILD.gn
index 09cba5e4..aff4ad1 100644
--- a/chrome/browser/themes/BUILD.gn
+++ b/chrome/browser/themes/BUILD.gn
@@ -45,9 +45,11 @@
     "//components/resources:components_scaled_resources",
     "//components/sync/protocol",
     "//components/sync_preferences",
+    "//components/tab_groups",
     "//content/public/browser",
     "//third_party/abseil-cpp:absl",
     "//ui/color",
+    "//ui/color/dynamic_color",
     "//ui/gfx",
     "//ui/native_theme",
   ]
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h
index cede739a..b709963 100644
--- a/chrome/browser/themes/browser_theme_pack.h
+++ b/chrome/browser/themes/browser_theme_pack.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <array>
 #include <map>
 #include <memory>
 #include <string>
@@ -19,9 +20,11 @@
 #include "base/values.h"
 #include "chrome/browser/themes/custom_theme_supplier.h"
 #include "chrome/common/themes/autogenerated_theme_util.h"
+#include "components/tab_groups/tab_group_color.h"
 #include "extensions/common/extension.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_scale_factor.h"
+#include "ui/color/dynamic_color/palette_factory.h"
 #include "ui/gfx/color_utils.h"
 
 namespace base {
@@ -348,6 +351,23 @@
   raw_ptr<DisplayPropertyPair, DanglingUntriaged | AllowPtrArithmetic>
       display_properties_ = nullptr;
 
+  struct TabGroupColorPaletteShadesPair {
+    // The `TabGroupColorId` that is to be overridden/customized.
+    int32_t id = -1;
+    // The shades generated based on the specified hue. These shades will be
+    // used to customize this `id`.
+    std::array<SkColor, ui::kGeneratedShadesCount> shades{};
+  };
+
+  // Number of color options in the tab group color palette.
+  static constexpr size_t kTabGroupColorPaletteLength =
+      static_cast<size_t>(tab_groups::TabGroupColorId::kNumEntries);
+
+  // This array stores an instance for each of the tab group colors that are
+  // overridden by the theme.
+  std::array<TabGroupColorPaletteShadesPair, kTabGroupColorPaletteLength>
+      tab_group_color_palette_shades_{};
+
   // A list of included source images. A pointer to a -1 terminated array of
   // our persistent IDs. The IDs are `int`s, but must be wrapped in a struct so
   // that `#pragma pack` above applies.
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.cc
index dbe8263..1011aa9 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.cc
@@ -13,7 +13,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/types/pass_key.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller.h"
 #include "chrome/browser/password_manager/android/local_passwords_migration_warning_util.h"
 #include "chrome/browser/password_manager/android/password_manager_ui_util_android.h"
@@ -60,8 +59,7 @@
     std::unique_ptr<password_manager::PasswordCredentialFiller> filler,
     const password_manager::PasswordForm* form_to_fill,
     autofill::FieldRendererId focused_field_renderer_id,
-    ShowHybridOption should_show_hybrid_option,
-    std::unique_ptr<PasswordAccessLossWarningBridge> data_loss_warning_bridge)
+    ShowHybridOption should_show_hybrid_option)
     : password_client_(password_client),
       web_contents_(web_contents),
       authenticator_(std::move(authenticator)),
@@ -69,8 +67,7 @@
       filler_(std::move(filler)),
       form_to_fill_(form_to_fill),
       focused_field_renderer_id_(focused_field_renderer_id),
-      should_show_hybrid_option_(should_show_hybrid_option),
-      access_loss_warning_bridge_(std::move(data_loss_warning_bridge)) {}
+      should_show_hybrid_option_(should_show_hybrid_option) {}
 
 TouchToFillControllerAutofillDelegate::TouchToFillControllerAutofillDelegate(
     ChromePasswordManagerClient* password_client,
@@ -93,8 +90,6 @@
       form_to_fill_(form_to_fill),
       focused_field_renderer_id_(focused_field_renderer_id),
       should_show_hybrid_option_(should_show_hybrid_option),
-      access_loss_warning_bridge_(
-          std::make_unique<PasswordAccessLossWarningBridgeImpl>()),
       source_id_(password_client->web_contents()
                      ->GetPrimaryMainFrame()
                      ->GetPageUkmSourceId()) {}
@@ -297,15 +292,7 @@
 
 void TouchToFillControllerAutofillDelegate::FillCredential(
     const UiCredential& credential) {
-  // Do not trigger autosubmission if the password migration warning is being
-  // shown because it interrupts the nomal workflow.
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
-  PrefService* prefs = profile->GetPrefs();
-  filler_->UpdateTriggerSubmission(
-      ShouldTriggerSubmission() &&
-      !access_loss_warning_bridge_->ShouldShowAccessLossNoticeSheet(
-          prefs, /*called_at_startup=*/false));
+  filler_->UpdateTriggerSubmission(ShouldTriggerSubmission());
   filler_->FillUsernameAndPassword(
       credential.username(), credential.password(),
       base::BindOnce(
@@ -316,18 +303,6 @@
 void TouchToFillControllerAutofillDelegate::OnFillingCredentialComplete(
     const std::u16string& username,
     bool triggered_submission) {
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
-  PrefService* prefs = profile->GetPrefs();
-  if (access_loss_warning_bridge_->ShouldShowAccessLossNoticeSheet(
-          prefs, /*called_at_startup=*/false)) {
-    access_loss_warning_bridge_->MaybeShowAccessLossNoticeSheet(
-        prefs, web_contents_->GetTopLevelNativeWindow(), profile,
-        /*called_at_startup=*/false,
-        password_manager_android_util::PasswordAccessLossWarningTriggers::
-            kTouchToFill);
-  }
-
   if (triggered_submission) {
     password_client_->StartSubmissionTrackingAfterTouchToFill(username);
   }
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.h b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.h
index bc176fe..9bcdecf 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.h
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/types/pass_key.h"
 #include "base/types/strong_alias.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_bridge.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller.h"
 #include "chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_delegate.h"
@@ -51,7 +50,6 @@
     : public TouchToFillControllerDelegate {
  public:
   using ShowHybridOption = base::StrongAlias<struct ShowHybridOptionTag, bool>;
-  using ShowDataLossWarningCallback = base::RepeatingCallback<void(void)>;
 
   // The action a user took when interacting with the Touch To Fill sheet.
   //
@@ -95,9 +93,7 @@
       std::unique_ptr<password_manager::PasswordCredentialFiller> filler,
       const password_manager::PasswordForm* form_to_fill,
       autofill::FieldRendererId focused_field_renderer_id,
-      ShowHybridOption should_show_hybrid_option,
-      std::unique_ptr<PasswordAccessLossWarningBridge>
-          data_loss_warning_bridge);
+      ShowHybridOption should_show_hybrid_option);
 
   TouchToFillControllerAutofillDelegate(
       ChromePasswordManagerClient* password_client,
@@ -183,10 +179,6 @@
   // Whether the controller should show an option for passkey hybrid sign-in.
   ShowHybridOption should_show_hybrid_option_ = ShowHybridOption(false);
 
-  // Bridge used to show the data loss warning (expected to be shown after
-  // filling user's credentials).
-  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge_;
-
   ukm::SourceId source_id_ = ukm::kInvalidSourceId;
 };
 
diff --git a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate_unittest.cc b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate_unittest.cc
index eceafc0..f59d23fc 100644
--- a/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate_unittest.cc
+++ b/chrome/browser/touch_to_fill/password_manager/touch_to_fill_controller_autofill_delegate_unittest.cc
@@ -19,7 +19,6 @@
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "base/types/pass_key.h"
-#include "chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_bridge.h"
 #include "chrome/browser/password_manager/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller_test_helper.h"
 #include "chrome/browser/password_manager/android/password_manager_launcher_android.h"
@@ -196,16 +195,12 @@
         .WillByDefault(Return(submission_readiness));
     auto authenticator = std::make_unique<MockDeviceAuthenticator>();
     authenticator_ = authenticator.get();
-    std::unique_ptr<MockPasswordAccessLossWarningBridge> mock_bridge =
-        std::make_unique<MockPasswordAccessLossWarningBridge>();
-    mock_access_loss_warning_bridge_ = mock_bridge.get();
 
     return std::make_unique<TouchToFillControllerAutofillDelegate>(
         base::PassKey<TouchToFillControllerAutofillTest>(), &client_,
         web_contents(), std::move(authenticator),
         webauthn_credentials_delegate_.AsWeakPtr(), std::move(filler),
-        form_to_fill, focused_field_renderer_id, should_show_hybrid_option,
-        std::move(mock_bridge));
+        form_to_fill, focused_field_renderer_id, should_show_hybrid_option);
   }
 
   password_manager::MockWebAuthnCredentialsDelegate&
@@ -222,10 +217,6 @@
     return &form_to_fill_;
   }
 
-  MockPasswordAccessLossWarningBridge* mock_access_loss_warning_bridge() {
-    return mock_access_loss_warning_bridge_;
-  }
-
   AcknowledgeGroupedCredentialSheetControllerTestHelper&
   acknowledge_grouped_credential_sheet_helper() {
     return grouped_credential_sheet_helper_;
@@ -260,7 +251,6 @@
   std::unique_ptr<TouchToFillController> touch_to_fill_controller_;
   base::test::ScopedFeatureList scoped_feature_list_{
       password_manager::features::kBiometricTouchToFill};
-  raw_ptr<MockPasswordAccessLossWarningBridge> mock_access_loss_warning_bridge_;
   raw_ptr<MockPasswordCredentialFiller> weak_filler_;
   password_manager::PasswordForm form_to_fill_;
   AcknowledgeGroupedCredentialSheetControllerTestHelper
@@ -327,43 +317,6 @@
   touch_to_fill_controller().OnCredentialSelected(credentials[0]);
 }
 
-TEST_F(TouchToFillControllerAutofillTest, FillingShowsAccessLossWarning) {
-  UiCredential credentials[] = {
-      MakeUiCredential({.username = "alice", .password = "p4ssw0rd"})};
-  auto filler_to_pass = CreateMockFiller();
-
-  EXPECT_CALL(view(), Show(Eq(GURL(kExampleCom)), IsOriginSecure(true),
-                           ElementsAreArray(credentials),
-                           ElementsAreArray(std::vector<PasskeyCredential>()),
-                           TouchToFillView::kNone));
-  Show(credentials, {},
-       MakeTouchToFillControllerDelegate(
-           autofill::mojom::SubmissionReadinessState::kTwoFields,
-           std::move(filler_to_pass), form_to_fill(),
-           form_to_fill()->password_element_renderer_id,
-           TouchToFillControllerAutofillDelegate::ShowHybridOption(false)),
-       /*cred_man_delegate=*/nullptr);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(testing::Return(true));
-
-  EXPECT_CALL(*last_mock_filler(),
-              FillUsernameAndPassword(std::u16string(u"alice"),
-                                      std::u16string(u"p4ssw0rd"), _))
-      .WillOnce(RunOnceCallback<2>(/*trigger_submission=*/false));
-  EXPECT_CALL(*last_mock_filler(), UpdateTriggerSubmission(false));
-  EXPECT_CALL(client(), StartSubmissionTrackingAfterTouchToFill(_)).Times(0);
-  EXPECT_CALL(*mock_access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet(
-                  profile()->GetPrefs(), _, profile(),
-                  /*called_at_startup=*/false,
-                  password_manager_android_util::
-                      PasswordAccessLossWarningTriggers::kTouchToFill));
-
-  touch_to_fill_controller().OnCredentialSelected(credentials[0]);
-}
-
 TEST_F(TouchToFillControllerAutofillTest, Dont_Submit_With_Empty_Username) {
   UiCredential credentials[] = {
       MakeUiCredential({.username = "", .password = "p4ssw0rd"}),
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index fa990963..0d635e59 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -670,10 +670,16 @@
   ]
 
   if (!is_android || is_desktop_android) {
+    # Cross-platform dependencies.
     deps += [
       "//chrome/browser/ui/browser_window",
       "//chrome/browser/ui/browser_window/internal",
     ]
+
+    # Desktop-Android-only dependencies.
+    if (is_desktop_android) {
+      deps += [ "//chrome/browser/ui/android/extensions/windowing/internal" ]
+    }
   }
 
   # TODO(crbug.com/413572035): Move into build files of the actual
@@ -880,7 +886,6 @@
       "//chrome/browser/keyboard_accessory/android:public",
       "//chrome/browser/notifications/scheduler/public",
       "//chrome/browser/password_manager/android:utils",
-      "//chrome/browser/password_manager/android/access_loss:public",
       "//chrome/browser/resources/feed_internals:resources",
       "//chrome/browser/touch_to_fill/autofill/android",
       "//chrome/browser/ui/android/autofill/internal:jni_headers",
@@ -1631,6 +1636,8 @@
       "//chrome/browser/ui/webui/new_tab_footer:impl",
       "//chrome/browser/ui/webui/new_tab_page/composebox",
       "//chrome/browser/ui/webui/new_tab_page/ntp_promo",
+      "//chrome/browser/ui/webui/password_manager:mojo_bindings",
+      "//chrome/browser/ui/webui/password_manager:password_manager_ui_handler",
       "//chrome/browser/ui/webui/privacy_sandbox",
       "//chrome/browser/ui/webui/searchbox",
       "//chrome/browser/ui/webui/settings",
diff --git a/chrome/browser/ui/actions/tools/dump_actions.cc b/chrome/browser/ui/actions/tools/dump_actions.cc
index d45796d..fb7da275 100644
--- a/chrome/browser/ui/actions/tools/dump_actions.cc
+++ b/chrome/browser/ui/actions/tools/dump_actions.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 // This command-line program dumps the computed values of all actiop IDs to
 // stdout.
 
@@ -17,6 +12,7 @@
 #include <iostream>
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/actions/chrome_action_id.h"
 #include "ui/actions/action_id.h"
@@ -51,7 +47,7 @@
   for (actions::ActionId id = actions::kActionsStart; id < kChromeActionsEnd;
        ++id) {
     std::cout << std::setfill(' ') << std::left;
-    std::cout << std::setw(longest_name) << enum_names[id] << '\n';
+    std::cout << std::setw(longest_name) << UNSAFE_TODO(enum_names[id]) << '\n';
   }
 
   std::cout.flush();
diff --git a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.cc b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.cc
index 10f94a8..bde0eab 100644
--- a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.cc
+++ b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.cc
@@ -130,11 +130,7 @@
         Java_AutofillKeyboardAccessoryViewBridge_createAutofillSuggestion(
             env, label, sublabel, android_icon_id,
             base::to_underlying(suggestion.type),
-            // These nullptr arguments are passed because pure virtual methods
-            // cannot have default parameters.
-            controller_->GetRemovalConfirmationText(
-                i, /* title= */ nullptr, /* body= */ nullptr,
-                /* confirm_button_text= */ nullptr),
+            controller_->GetRemovalConfirmationText(i, nullptr),
             suggestion.iph_metadata.feature
                 ? suggestion.iph_metadata.feature->name
                 : "",
@@ -155,13 +151,14 @@
 void AutofillKeyboardAccessoryViewImpl::ConfirmDeletion(
     const std::u16string& confirmation_title,
     const std::u16string& confirmation_body,
+    const std::u16string& confirmation_body_link,
     const std::u16string& confirmation_button_text,
     base::OnceCallback<void(bool)> deletion_callback) {
   JNIEnv* env = base::android::AttachCurrentThread();
   deletion_callback_ = std::move(deletion_callback);
   Java_AutofillKeyboardAccessoryViewBridge_confirmDeletion(
       env, java_object_, confirmation_title, confirmation_body,
-      confirmation_button_text);
+      confirmation_body_link, confirmation_button_text);
 }
 
 void AutofillKeyboardAccessoryViewImpl::SuggestionSelected(JNIEnv* env,
diff --git a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.h b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.h
index fb73323..e3e7beb 100644
--- a/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.h
+++ b/chrome/browser/ui/android/autofill/autofill_keyboard_accessory_view_impl.h
@@ -43,6 +43,7 @@
   void ConfirmDeletion(
       const std::u16string& confirmation_title,
       const std::u16string& confirmation_body,
+      const std::u16string& confirmation_body_link,
       const std::u16string& confirm_button_text,
       base::OnceCallback<void(bool)> deletion_callback) override;
 
diff --git a/chrome/browser/ui/android/autofill/internal/BUILD.gn b/chrome/browser/ui/android/autofill/internal/BUILD.gn
index 7d926254..717b40f 100644
--- a/chrome/browser/ui/android/autofill/internal/BUILD.gn
+++ b/chrome/browser/ui/android/autofill/internal/BUILD.gn
@@ -25,17 +25,21 @@
     "java/src/org/chromium/chrome/browser/ui/autofill/OtpVerificationDialogView.java",
     "java/src/org/chromium/chrome/browser/ui/autofill/OtpVerificationDialogViewBinder.java",
     "java/src/org/chromium/chrome/browser/ui/autofill/data/AuthenticatorOption.java",
+    "java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridge.java",
+    "java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinator.java",
   ]
   deps = [
     ":java_resources",
     "//base:base_java",
     "//build/android:build_java",
     "//components/autofill/android:main_autofill_java",
+    "//content/public/android:content_full_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_core_core_java",
     "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//third_party/jni_zero:jni_zero_java",
     "//ui/android:ui_java",
+    "//url:url_java",
   ]
 
   resources_package = "org.chromium.chrome.browser.ui.autofill.internal"
@@ -62,6 +66,8 @@
     "java/src/org/chromium/chrome/browser/ui/autofill/AutofillErrorDialogBridgeTest.java",
     "java/src/org/chromium/chrome/browser/ui/autofill/AutofillProgressDialogBridgeTest.java",
     "java/src/org/chromium/chrome/browser/ui/autofill/OtpVerificationDialogTest.java",
+    "java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridgeTest.java",
+    "java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinatorTest.java",
   ]
   deps = [
     ":java",
@@ -71,9 +77,11 @@
     "//base/test:test_support_java",
     "//chrome/test/android:chrome_java_test_support_common",
     "//components/autofill/android:main_autofill_java",
+    "//content/public/android:content_full_java",
     "//third_party/androidx:androidx_core_core_java",
     "//third_party/androidx:androidx_recyclerview_recyclerview_java",
     "//third_party/androidx:androidx_test_core_java",
+    "//third_party/androidx:androidx_test_ext_junit_java",
     "//third_party/androidx:androidx_test_runner_java",
     "//third_party/google-truth:google_truth_java",
     "//third_party/jni_zero:jni_zero_java",
diff --git a/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridge.java b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridge.java
new file mode 100644
index 0000000..3ee257a
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridge.java
@@ -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.
+
+package org.chromium.chrome.browser.ui.autofill.ephemeraltab;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.JNINamespace;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.content_public.browser.WebContents;
+
+/** Bridge for the Emphemeral Tab bottom sheet. */
+@JNINamespace("autofill")
+@NullMarked
+class PaymentsWindowBridge {
+    private PaymentsWindowCoordinator mPaymentsWindowCoordinator;
+
+    @CalledByNative
+    PaymentsWindowBridge(WebContents webContents) {
+        mPaymentsWindowCoordinator = new PaymentsWindowCoordinator(webContents);
+    }
+
+    @CalledByNative
+    public void openEphemeralTab() {
+        mPaymentsWindowCoordinator.openEphemeralTab();
+    }
+
+    PaymentsWindowCoordinator getPaymentsWindowCoordinatorForTesting() {
+        return mPaymentsWindowCoordinator;
+    }
+
+    void setPaymentsWindowCoordinatorForTesting(
+            PaymentsWindowCoordinator paymentsWindowCoordinator) {
+        mPaymentsWindowCoordinator = paymentsWindowCoordinator;
+    }
+}
diff --git a/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridgeTest.java b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridgeTest.java
new file mode 100644
index 0000000..6ffb71e
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowBridgeTest.java
@@ -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.
+
+package org.chromium.chrome.browser.ui.autofill.ephemeraltab;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.content_public.browser.WebContents;
+
+/** Tests for {@link PaymentsWindowBridge}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class PaymentsWindowBridgeTest {
+    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+    @Mock private WebContents mWebContents;
+    @Mock private PaymentsWindowCoordinator mPaymentsWindowCoordinator;
+    private PaymentsWindowBridge mPaymentsWindowBridge;
+
+    @Before
+    public void setUp() {
+        mPaymentsWindowBridge = new PaymentsWindowBridge(mWebContents);
+    }
+
+    @Test
+    public void testPaymentsWindowCoordinator() {
+        assertNotNull(mPaymentsWindowBridge.getPaymentsWindowCoordinatorForTesting());
+    }
+
+    @Test
+    public void testOpenEphemeralTab() {
+        mPaymentsWindowBridge.setPaymentsWindowCoordinatorForTesting(mPaymentsWindowCoordinator);
+        mPaymentsWindowBridge.openEphemeralTab();
+        verify(mPaymentsWindowCoordinator).openEphemeralTab();
+    }
+}
diff --git a/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinator.java b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinator.java
new file mode 100644
index 0000000..de266f7c
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinator.java
@@ -0,0 +1,31 @@
+// 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.ui.autofill.ephemeraltab;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.content_public.browser.WebContents;
+
+/** The coordinator for triggering the Ephemeral Tab. */
+@NullMarked
+class PaymentsWindowCoordinator {
+    private final WebContents mWebContents;
+
+    /** Constructs a new {@code PaymentsWindowCoordinator} from the provided {@code WebContents}. */
+    PaymentsWindowCoordinator(WebContents webContents) {
+        mWebContents = webContents;
+    }
+
+    /**
+     * Attempts to open an ephemeral tab; it involves obtaining the {@code WindowAndroid} from the
+     * managed {@code WebContents} and using it to present the UI.
+     */
+    void openEphemeralTab() {
+        // TODO(crbug.com/430575808): Implement the connection to trigger the Ephemeral Tab.
+    }
+
+    WebContents getWebContentsForTesting() {
+        return mWebContents;
+    }
+}
diff --git a/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinatorTest.java b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinatorTest.java
new file mode 100644
index 0000000..7c757f86
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/ephemeraltab/PaymentsWindowCoordinatorTest.java
@@ -0,0 +1,41 @@
+// 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.ui.autofill.ephemeraltab;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.content_public.browser.WebContents;
+
+/** Tests for {@link PaymentsWindowCoordinator}. */
+@RunWith(BaseRobolectricTestRunner.class)
+public class PaymentsWindowCoordinatorTest {
+    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+    @Mock private WebContents mWebContents;
+    private PaymentsWindowCoordinator mCoordinator;
+
+    @Before
+    public void setUp() {
+        mCoordinator = new PaymentsWindowCoordinator(mWebContents);
+    }
+
+    @Test
+    public void testWebContents() {
+        assertEquals(mCoordinator.getWebContentsForTesting(), mWebContents);
+    }
+
+    @Test
+    public void testOpenEphemeralTab() {
+        mCoordinator.openEphemeralTab();
+    }
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/BUILD.gn b/chrome/browser/ui/android/extensions/windowing/BUILD.gn
new file mode 100644
index 0000000..7bd2fd68
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/BUILD.gn
@@ -0,0 +1,24 @@
+# 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/android/rules.gni")
+import("//chrome/android/features/android_library_factory_tmpl.gni")
+
+# Public Java interfaces
+android_library("java") {
+  sources = [ "java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridge.java" ]
+  deps = [
+    "//build/android:build_java",
+    "//chrome/browser/ui/browser_window:java",
+  ]
+}
+
+# Public Java factory
+android_library_factory("factory_java") {
+  sources = [ "internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeFactory.java" ]
+  deps = [
+    ":java",
+    "//chrome/browser/ui/browser_window:java",
+  ]
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/OWNERS b/chrome/browser/ui/android/extensions/windowing/OWNERS
new file mode 100644
index 0000000..8698af0
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/OWNERS
@@ -0,0 +1,3 @@
+linyuh@google.com
+nyquist@chromium.org
+skavuluru@google.com
diff --git a/chrome/browser/ui/android/extensions/windowing/README.md b/chrome/browser/ui/android/extensions/windowing/README.md
new file mode 100644
index 0000000..3e24edda
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/README.md
@@ -0,0 +1,4 @@
+chrome/browser/ui/android/extensions/windowing
+==================
+
+This directory contains Android code for extension-specific windowing logic.
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn b/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn
new file mode 100644
index 0000000..433510a3
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/internal/BUILD.gn
@@ -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.
+
+import("//build/config/android/rules.gni")
+import("//build/config/chrome_build.gni")
+import("//third_party/jni_zero/jni_zero.gni")
+
+assert(is_desktop_android)
+
+source_set("internal") {
+  sources = [ "extension_window_controller_bridge.cc" ]
+  deps = [
+    ":jni",
+    "//base",
+  ]
+}
+
+android_library("java") {
+  visibility = [
+    ":*",
+    "//chrome/android:chrome_all_java",
+    "//chrome/browser/ui/android/extensions/windowing/test:native_unit_test_support_java",
+  ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeFactory.java",
+    "java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java",
+  ]
+  deps = [
+    "//build/android:build_java",
+    "//chrome/browser/ui/android/extensions/windowing:java",
+    "//chrome/browser/ui/browser_window:java",
+    "//third_party/jni_zero:jni_zero_java",
+  ]
+  srcjar_deps = [ ":jni" ]
+}
+
+generate_jni("jni") {
+  sources = [ "java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java" ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "extension_window_controller_bridge_unittest.cc" ]
+  deps = [
+    ":internal",
+    "//base",
+    "//chrome/browser/ui/android/extensions/windowing/test:native_unit_test_support_java",
+    "//chrome/browser/ui/android/extensions/windowing/test:native_unit_test_support_jni",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc
new file mode 100644
index 0000000..798860a
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.cc
@@ -0,0 +1,41 @@
+// 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 "chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/ui/android/extensions/windowing/internal/jni/ExtensionWindowControllerBridgeImpl_jni.h"
+
+namespace {
+using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+}  // namespace
+
+// Implements Java |ExtensionWindowControllerBridgeImpl.Natives#create|
+static jlong JNI_ExtensionWindowControllerBridgeImpl_Create(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& caller) {
+  return reinterpret_cast<intptr_t>(
+      new ExtensionWindowControllerBridge(env, caller));
+}
+
+ExtensionWindowControllerBridge::ExtensionWindowControllerBridge(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>&
+        java_extension_window_controller_bridge) {
+  java_extension_window_controller_bridge_.Reset(
+      env, java_extension_window_controller_bridge);
+}
+
+ExtensionWindowControllerBridge::~ExtensionWindowControllerBridge() {
+  Java_ExtensionWindowControllerBridgeImpl_clearNativePtr(
+      AttachCurrentThread(), java_extension_window_controller_bridge_);
+}
+
+void ExtensionWindowControllerBridge::Destroy(JNIEnv* env) {
+  delete this;
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h
new file mode 100644
index 0000000..409e211
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h
@@ -0,0 +1,36 @@
+// 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 CHROME_BROWSER_UI_ANDROID_EXTENSIONS_WINDOWING_INTERNAL_EXTENSION_WINDOW_CONTROLLER_BRIDGE_H_
+#define CHROME_BROWSER_UI_ANDROID_EXTENSIONS_WINDOWING_INTERNAL_EXTENSION_WINDOW_CONTROLLER_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+
+// Native class for the Java |ExtensionWindowControllerBridge|.
+//
+// The primary purpose of this class is to own a cross-platform
+// |extensions::WindowController| and allow the Java class to communicate with
+// it.
+class ExtensionWindowControllerBridge final {
+ public:
+  ExtensionWindowControllerBridge(JNIEnv* env,
+                                  const base::android::JavaParamRef<jobject>&
+                                      java_extension_window_controller_bridge);
+  ExtensionWindowControllerBridge(const ExtensionWindowControllerBridge&) =
+      delete;
+  ExtensionWindowControllerBridge& operator=(
+      const ExtensionWindowControllerBridge&) = delete;
+  ~ExtensionWindowControllerBridge();
+
+  // Implements Java |ExtensionWindowControllerBridgeImpl.Natives#destroy|.
+  void Destroy(JNIEnv* env);
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject>
+      java_extension_window_controller_bridge_;
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_EXTENSIONS_WINDOWING_INTERNAL_EXTENSION_WINDOW_CONTROLLER_BRIDGE_H_
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc
new file mode 100644
index 0000000..0b8d1eb
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge_unittest.cc
@@ -0,0 +1,95 @@
+// 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 "chrome/browser/ui/android/extensions/windowing/internal/extension_window_controller_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/ui/android/extensions/windowing/test/native_unit_test_support_jni/ExtensionWindowControllerBridgeNativeUnitTestSupport_jni.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaGlobalRef;
+}  // namespace
+
+class ExtensionWindowControllerBridgeUnitTest : public testing::Test {
+ public:
+  ExtensionWindowControllerBridgeUnitTest() = default;
+  ~ExtensionWindowControllerBridgeUnitTest() override = default;
+
+  void SetUp() override {
+    java_test_support_.Reset(
+        Java_ExtensionWindowControllerBridgeNativeUnitTestSupport_Constructor(
+            AttachCurrentThread()));
+  }
+
+  void TearDown() override { InvokeJavaOnTaskRemoved(); }
+
+  void InvokeJavaOnAddedToTask() const {
+    Java_ExtensionWindowControllerBridgeNativeUnitTestSupport_invokeOnAddedToTask(
+        AttachCurrentThread(), java_test_support_);
+  }
+
+  void InvokeJavaOnTaskRemoved() const {
+    Java_ExtensionWindowControllerBridgeNativeUnitTestSupport_invokeOnTaskRemoved(
+        AttachCurrentThread(), java_test_support_);
+  }
+
+  ExtensionWindowControllerBridge* InvokeJavaGetNativePtrForTesting() const {
+    return reinterpret_cast<ExtensionWindowControllerBridge*>(
+        Java_ExtensionWindowControllerBridgeNativeUnitTestSupport_invokeGetNativePtrForTesting(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+ private:
+  ScopedJavaGlobalRef<jobject> java_test_support_;
+};
+
+TEST_F(ExtensionWindowControllerBridgeUnitTest,
+       JavaOnAddedToTaskCreatesNativeObj) {
+  // Act.
+  InvokeJavaOnAddedToTask();
+
+  // Assert.
+  ExtensionWindowControllerBridge* native_ptr =
+      InvokeJavaGetNativePtrForTesting();
+  EXPECT_NE(nullptr, native_ptr);
+}
+
+TEST_F(ExtensionWindowControllerBridgeUnitTest,
+       CallingJavaOnAddedToTaskTwiceFails) {
+  EXPECT_DEATH(
+      {
+        InvokeJavaOnAddedToTask();
+        InvokeJavaOnAddedToTask();
+      },
+      /*matcher=*/"");
+}
+
+TEST_F(ExtensionWindowControllerBridgeUnitTest,
+       JavaOnTaskRemovedClearsNativePtrValueInJava) {
+  // Arrange.
+  InvokeJavaOnAddedToTask();
+
+  // Act.
+  InvokeJavaOnTaskRemoved();
+
+  // Assert.
+  EXPECT_EQ(nullptr, InvokeJavaGetNativePtrForTesting());
+}
+
+TEST_F(ExtensionWindowControllerBridgeUnitTest,
+       CallingJavaOnTaskRemovedTwiceDoesNotCrash) {
+  // Arrange.
+  InvokeJavaOnAddedToTask();
+
+  // Act.
+  InvokeJavaOnTaskRemoved();
+  InvokeJavaOnTaskRemoved();
+
+  // Assert.
+  EXPECT_EQ(nullptr, InvokeJavaGetNativePtrForTesting());
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeFactory.java b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeFactory.java
new file mode 100644
index 0000000..c04f481
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeFactory.java
@@ -0,0 +1,27 @@
+// 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.ui.extensions.windowing;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
+
+/** Factory for creating an {@link ExtensionWindowControllerBridge}. */
+@NullMarked
+public final class ExtensionWindowControllerBridgeFactory {
+    private ExtensionWindowControllerBridgeFactory() {}
+
+    /**
+     * Creates an {@link ExtensionWindowControllerBridge} for the given {@link ChromeAndroidTask}.
+     *
+     * <p>Note: this class is compiled using the {@code android_library_factory} GN template, so
+     * this method will return null if {@link ExtensionWindowControllerBridgeImpl} isn't compiled
+     * into the build.
+     */
+    @Nullable
+    public static ExtensionWindowControllerBridge create(ChromeAndroidTask chromeAndroidTask) {
+        return new ExtensionWindowControllerBridgeImpl(chromeAndroidTask);
+    }
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java
new file mode 100644
index 0000000..82f1fa19
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java
@@ -0,0 +1,58 @@
+// 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.ui.extensions.windowing;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.NativeMethods;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
+
+/** Implements {@link ExtensionWindowControllerBridge}. */
+@NullMarked
+final class ExtensionWindowControllerBridgeImpl implements ExtensionWindowControllerBridge {
+
+    @SuppressWarnings("UnusedVariable")
+    private final ChromeAndroidTask mChromeAndroidTask;
+
+    private long mNativeExtensionWindowControllerBridge;
+
+    ExtensionWindowControllerBridgeImpl(ChromeAndroidTask chromeAndroidTask) {
+        mChromeAndroidTask = chromeAndroidTask;
+    }
+
+    @Override
+    public void onAddedToTask() {
+        assert mNativeExtensionWindowControllerBridge == 0
+                : "ExtensionWindowControllerBridge is already added to a task.";
+
+        mNativeExtensionWindowControllerBridge =
+                ExtensionWindowControllerBridgeImplJni.get().create(this);
+    }
+
+    @Override
+    public void onTaskRemoved() {
+        if (mNativeExtensionWindowControllerBridge != 0) {
+            ExtensionWindowControllerBridgeImplJni.get()
+                    .destroy(mNativeExtensionWindowControllerBridge);
+        }
+    }
+
+    long getNativePtrForTesting() {
+        return mNativeExtensionWindowControllerBridge;
+    }
+
+    @CalledByNative
+    private void clearNativePtr() {
+        mNativeExtensionWindowControllerBridge = 0;
+    }
+
+    @NativeMethods
+    interface Natives {
+        long create(ExtensionWindowControllerBridgeImpl caller);
+
+        void destroy(long nativeExtensionWindowControllerBridge);
+    }
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridge.java b/chrome/browser/ui/android/extensions/windowing/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridge.java
new file mode 100644
index 0000000..5d09b640
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridge.java
@@ -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.
+
+package org.chromium.chrome.browser.ui.extensions.windowing;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTaskFeature;
+
+/**
+ * Provides access to cross-platform extension windowing code for Java.
+ *
+ * <p>This interface extends {@link ChromeAndroidTaskFeature} so that the lifecycle of an instance
+ * will be in sync with that of a {@code ChromeAndroidTask}.
+ */
+@NullMarked
+public interface ExtensionWindowControllerBridge extends ChromeAndroidTaskFeature {}
diff --git a/chrome/browser/ui/android/extensions/windowing/test/BUILD.gn b/chrome/browser/ui/android/extensions/windowing/test/BUILD.gn
new file mode 100644
index 0000000..fd60b550
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/test/BUILD.gn
@@ -0,0 +1,24 @@
+# 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/android/rules.gni")
+import("//third_party/jni_zero/jni_zero.gni")
+
+android_library("native_unit_test_support_java") {
+  testonly = true
+  sources = [ "java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeNativeUnitTestSupport.java" ]
+  deps = [
+    "//build/android:build_java",
+    "//chrome/browser/ui/android/extensions/windowing/internal:java",
+    "//chrome/browser/ui/browser_window:java",
+    "//third_party/jni_zero:jni_zero_java",
+    "//third_party/mockito:mockito_java",
+  ]
+  srcjar_deps = [ ":native_unit_test_support_jni" ]
+}
+
+generate_jni("native_unit_test_support_jni") {
+  testonly = true
+  sources = [ "java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeNativeUnitTestSupport.java" ]
+}
diff --git a/chrome/browser/ui/android/extensions/windowing/test/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeNativeUnitTestSupport.java b/chrome/browser/ui/android/extensions/windowing/test/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeNativeUnitTestSupport.java
new file mode 100644
index 0000000..2e7e2b3
--- /dev/null
+++ b/chrome/browser/ui/android/extensions/windowing/test/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeNativeUnitTestSupport.java
@@ -0,0 +1,51 @@
+// 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.ui.extensions.windowing;
+
+import static org.mockito.Mockito.mock;
+
+import org.jni_zero.CalledByNative;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
+
+/**
+ * Supports {@code extension_window_controller_bridge_unittest.cc}.
+ *
+ * <p>The native unit test will use this class to:
+ *
+ * <ul>
+ *   <li>Instantiate a Java {@link ExtensionWindowControllerBridgeImpl} and its native counterpart;
+ *       and
+ *   <li>Test the Java methods in {@link ExtensionWindowControllerBridgeImpl}.
+ * </ul>
+ */
+@NullMarked
+final class ExtensionWindowControllerBridgeNativeUnitTestSupport {
+    private final ChromeAndroidTask mChromeAndroidTask;
+    private final ExtensionWindowControllerBridgeImpl mExtensionWindowControllerBridge;
+
+    @CalledByNative
+    private ExtensionWindowControllerBridgeNativeUnitTestSupport() {
+        mChromeAndroidTask = mock(ChromeAndroidTask.class);
+        mExtensionWindowControllerBridge =
+                new ExtensionWindowControllerBridgeImpl(mChromeAndroidTask);
+    }
+
+    @CalledByNative
+    private void invokeOnAddedToTask() {
+        mExtensionWindowControllerBridge.onAddedToTask();
+    }
+
+    @CalledByNative
+    private void invokeOnTaskRemoved() {
+        mExtensionWindowControllerBridge.onTaskRemoved();
+    }
+
+    @CalledByNative
+    private long invokeGetNativePtrForTesting() {
+        return mExtensionWindowControllerBridge.getNativePtrForTesting();
+    }
+}
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 66b4bbd..6dee2a1 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -851,42 +851,9 @@
       <message name="IDS_PASSWORDS_NOT_SECURE_FILLING_DETAILS" desc="The message of the dialog which is shown when the user attempts to enter obfuscated text to a regular text field.">
         To protect your privacy, Chrome will not autofill your password in this field.
       </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TITLE" desc="The title of the password access loss warning sheet when there is no GMS Core." formatter_data="android_java">
-        Google Password Manager will stop working on this device
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TEXT" desc="The text of the password access loss warning sheet when there is no GMS Core." formatter_data="android_java">
-        Passwords will stop working soon because Google Play services isn’t available. You can make a copy of your saved passwords before they stop working. <ph name="BEGIN_LINK">&lt;link&gt;</ph>Learn more<ph name="END_LINK">&lt;/link&gt;</ph>
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_BUTTON_TEXT" desc="The button text of the password access loss warning sheet when there is no GMS Core." formatter_data="android_java">
-        Export passwords
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TITLE" desc="The title of the password access loss warning sheet when the automatic password migration failed." formatter_data="android_java">
-        Fix problem with saved passwords
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TEXT" desc="The text of the password access loss warning sheet when the automatic password migration failed." formatter_data="android_java">
-        Some passwords on this device will stop working soon. You can move these passwords to Google Password Manager.
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_BUTTON_TEXT" desc="The button text of the password access loss warning sheet when the automatic password migration failed." formatter_data="android_java">
-        Help me fix this
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TITLE" desc="The title of the password access loss warning sheet when the GMS Core version doesn't support local passwords." formatter_data="android_java">
-        Update Google Play services
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TEXT" desc="The text of the password access loss warning sheet when the GMS Core version doesn't support local passwords." formatter_data="android_java">
-        Passwords may stop working soon on this device. To keep using your passwords, update Google Play services. <ph name="BEGIN_LINK">&lt;link&gt;</ph>Learn more<ph name="END_LINK">&lt;/link&gt;</ph>
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_WARNING_NO_UPM_TEXT" desc="The text of the password access loss warning sheet when the device doesn't have Google Play Services.">
-        Passwords will stop working soon on this device. To keep using your passwords, update Google Play services. <ph name="BEGIN_LINK">&lt;link&gt;</ph>Learn more<ph name="END_LINK">&lt;/link&gt;</ph>
-      </message>
       <message name="IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_BUTTON_TEXT" desc="The button text of the password access loss warning sheet when the GMS Core version doesn't support local passwords." formatter_data="android_java">
         Update
       </message>
-      <message name="IDS_PWD_ACCESS_LOSS_NOTIFICATION_NO_GMS_CORE_TEXT" desc="The text of the password access loss notification when there is no GMS Core." formatter_data="android_java">
-        Passwords will stop working soon because Google Play services isn’t available. You can make a copy of your saved passwords before they stop working.
-      </message>
-      <message name="IDS_PWD_ACCESS_LOSS_NOTIFICATION_UPDATE_GMS_CORE_TEXT" desc="The text of the password access loss notification when the GMS Core version doesn't support local passwords." formatter_data="android_java">
-        Passwords may stop working soon on this device. To keep using your passwords, update Google Play services.
-      </message>
       <message name="IDS_SOME_PASSWORDS_ARE_NOT_ACCESSIBLE_SUBTITLE" desc="Subtitle shown under the Google Password Manager entry point, when the password manager is available for the user, but they have unmigrated passwords left behind in Chrome.">
         Some of your passwords aren’t accessible
       </message>
@@ -962,45 +929,6 @@
       <message name="IDS_ACCESS_LOSS_UPDATE_GMS_TITLE" desc="The title of the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings having an outdated Goggle Play Services.">
         Update Google Play services
       </message>
-      <message name="IDS_ACCESS_LOSS_UPDATE_GMS_DESC" desc="The message in the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings having an outdated Goggle Play Services.">
-        Passwords may stop working soon on this device. To keep using your passwords, update Google Play services.
-      </message>
-      <message name="IDS_ACCESS_LOSS_NO_UPM_DESC" desc="The message in the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings having an outdated Goggle Play Services.">
-        Passwords will stop working soon on this device. To keep using your passwords, update Google Play services.
-      </message>
-      <message name="IDS_ACCESS_LOSS_FIX_PROBLEM_TITLE" desc="The title of the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings after failed local passwords migration to Google Play Services">
-        Fix problem with saved passwords
-      </message>
-      <message name="IDS_ACCESS_LOSS_FIX_PROBLEM_DESC" desc="The message in the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings after failed local passwords migration to Google Play Services">
-        Some passwords on this device will stop working soon. You can move these passwords to Google Password Manager.
-      </message>
-      <message name="IDS_ACCESS_LOSS_FIX_PROBLEM_POSITIVE_BUTTON_TEXT" desc="If the user has local passwords migration failed to Google Play services, they see the warning proposing them to fix this problem. This string is the agreement button text in the warning.">
-        Fix now
-      </message>
-      <message name="IDS_ACCESS_LOSS_NO_GMS_TITLE" desc="The title of the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings if no Google Play Services is installed on the phone.">
-        Google Password Manager will stop working on this device
-      </message>
-      <message name="IDS_ACCESS_LOSS_NO_GMS_DESC" desc="The message in the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings if no Google Play Services is installed on the phone.">
-        Passwords will stop working soon because Google Play services isn’t available. You can make a copy of your saved passwords before they stop working.
-      </message>
-      <message name="IDS_ACCESS_LOSS_NO_GMS_POSITIVE_BUTTON_TEXT" desc="If the user has no Google Play services installed on the phone, they see the modal dialog warning them that passwords will stop working soon and proposing them to export their paswords before that. This string is the agreement button text in the warning.">
-        Export passwords
-      </message>
-      <message name="IDS_ACCESS_LOSS_IMPORT_DIALOG_TITLE" desc="The title of the dialog instructing the user to import passwords into Google Password Manager.">
-        Next, import the passwords
-      </message>
-      <message name="IDS_ACCESS_LOSS_IMPORT_DIALOG_DESC" desc="The message of the dialog instructing the user to import passwords into Google Password Manager.">
-        Open Google Password Manager and go to settings. Select “Import“ and add the CSV file that contains your exported passwords.
-      </message>
-      <message name="IDS_ACCESS_LOSS_IMPORT_DIALOG_POSITIVE_BUTTON_TEXT" desc="The positive button text in the dialog instructing the user to import passwords into Google Password Manager.">
-        Take me there
-      </message>
-      <message name="IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_TITLE" desc="The title of the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings if no Google Play Services is installed on the phone and there are no passwords saved in the profile store.">
-        Google Password Manager will stop working soon on this device
-      </message>
-      <message name="IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_DESC" desc="The message in the password access loss warning shown in Settings when the user tries to navigate to the Password Manager settings if no Google Play Services is installed on the phone and there are no passwords saved in the profile store.">
-        Passwords will stop working soon because Google Play services isn’t available. To use passwords saved in your Google Account, sign in using another device, or go to passwords.google.com.
-      </message>
       <!-- Acknowledge grouped credential bottom sheet -->
       <message name="IDS_ACK_GROUPED_CRED_SHEET_OPENED" desc="The accessibility string to be announced by TalkBack right after the bottom sheet is opened.">
         Password suggestion confirmation
@@ -4359,6 +4287,9 @@
       <message name="IDS_MENU_NEW_WINDOW" desc="Menu item for opening a new window. [CHAR_LIMIT=27]">
         New window
       </message>
+      <message name="IDS_MENU_NEW_INCOGNITO_WINDOW" desc="Menu item for opening a new incognito window. [CHAR_LIMIT=27]">
+        New incognito window
+      </message>
       <message name="IDS_MENU_MOVE_TO_OTHER_WINDOW" desc="Menu item for moving the current tab into the other window. [CHAR_LIMIT=27]">
         Move to other window
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_DESC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_DESC.png.sha1
deleted file mode 100644
index 679bdc1c..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-1fe3c6d2b36def6a97a8953ee8e66ab46fff806a
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_POSITIVE_BUTTON_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_POSITIVE_BUTTON_TEXT.png.sha1
deleted file mode 100644
index 56c2f79..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_POSITIVE_BUTTON_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e01a9aa2dc8249e61d15aa792905b6feb43c71c1
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_TITLE.png.sha1
deleted file mode 100644
index 56c2f79..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_FIX_PROBLEM_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e01a9aa2dc8249e61d15aa792905b6feb43c71c1
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_DESC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_DESC.png.sha1
deleted file mode 100644
index 54f3ce4d..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d8d78033d06543c2b58af593efb1d45ca829b24e
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_POSITIVE_BUTTON_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_POSITIVE_BUTTON_TEXT.png.sha1
deleted file mode 100644
index 54f3ce4d..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_POSITIVE_BUTTON_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d8d78033d06543c2b58af593efb1d45ca829b24e
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_TITLE.png.sha1
deleted file mode 100644
index 54f3ce4d..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_IMPORT_DIALOG_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d8d78033d06543c2b58af593efb1d45ca829b24e
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_DESC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_DESC.png.sha1
deleted file mode 100644
index 228d357e..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-92862ec2d09c5dd17c8b26b0fe7f37751536e63d
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_DESC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_DESC.png.sha1
deleted file mode 100644
index 7a60782..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b1ce0004fd3d862ae7943b5ed17cbda03691e6e9
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_TITLE.png.sha1
deleted file mode 100644
index bc15496..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_NO_PASSWORDS_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6c55530e18cbf6feeb3e98220653cbf4290ea25c
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_POSITIVE_BUTTON_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_POSITIVE_BUTTON_TEXT.png.sha1
deleted file mode 100644
index 228d357e..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_POSITIVE_BUTTON_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-92862ec2d09c5dd17c8b26b0fe7f37751536e63d
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_TITLE.png.sha1
deleted file mode 100644
index 228d357e..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_GMS_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-92862ec2d09c5dd17c8b26b0fe7f37751536e63d
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_UPM_DESC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_UPM_DESC.png.sha1
deleted file mode 100644
index 24557d46..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_NO_UPM_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ac3b715ca50e8c01f418e4965a8da5866aebac29
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_UPDATE_GMS_DESC.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_UPDATE_GMS_DESC.png.sha1
deleted file mode 100644
index c2c9f931..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ACCESS_LOSS_UPDATE_GMS_DESC.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f01255968886894c348e02ec3276d0a247c6a4c7
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_NEW_INCOGNITO_WINDOW.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_NEW_INCOGNITO_WINDOW.png.sha1
new file mode 100644
index 0000000..c2949bc
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_NEW_INCOGNITO_WINDOW.png.sha1
@@ -0,0 +1 @@
+7c233ca6dc1ea390b155437e9d6a6a9a0edc3fcc
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_NOTIFICATION_NO_GMS_CORE_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_NOTIFICATION_NO_GMS_CORE_TEXT.png.sha1
deleted file mode 100644
index 424896f..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_NOTIFICATION_NO_GMS_CORE_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d174cdbb7de61fd152fb56115b2e1633eba77a36
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_NOTIFICATION_UPDATE_GMS_CORE_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_NOTIFICATION_UPDATE_GMS_CORE_TEXT.png.sha1
deleted file mode 100644
index c0c6ba57..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_NOTIFICATION_UPDATE_GMS_CORE_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c4adaea25a52f4d025a896a44c7a0a0ab69a8c10
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_BUTTON_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_BUTTON_TEXT.png.sha1
deleted file mode 100644
index 1ce6cc88..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_BUTTON_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b1d596a2b59efa803b0c703b96c0bd0e76b60397
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TEXT.png.sha1
deleted file mode 100644
index 1ce6cc88..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b1d596a2b59efa803b0c703b96c0bd0e76b60397
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TITLE.png.sha1
deleted file mode 100644
index 1ce6cc88..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_MANUAL_MIGRATION_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b1d596a2b59efa803b0c703b96c0bd0e76b60397
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_BUTTON_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_BUTTON_TEXT.png.sha1
deleted file mode 100644
index 6ee2a50..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_BUTTON_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6cb49a71cdf2e040b00739354b56c1a15018bf18
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TEXT.png.sha1
deleted file mode 100644
index 6ee2a50..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6cb49a71cdf2e040b00739354b56c1a15018bf18
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TITLE.png.sha1
deleted file mode 100644
index 6ee2a50..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_GMS_CORE_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6cb49a71cdf2e040b00739354b56c1a15018bf18
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_UPM_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_UPM_TEXT.png.sha1
deleted file mode 100644
index 216c2bdabb..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_NO_UPM_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-adf3b2f1c6e9a785b52c2329060bff1b81a6069a
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TEXT.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TEXT.png.sha1
deleted file mode 100644
index 064f05e..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-66eac060a4c46217d9c1ad73122cf31af1226739
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TITLE.png.sha1
deleted file mode 100644
index 064f05e..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PWD_ACCESS_LOSS_WARNING_UPDATE_GMS_CORE_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-66eac060a4c46217d9c1ad73122cf31af1226739
\ No newline at end of file
diff --git a/chrome/browser/ui/android/webid/account_selection_view_android.cc b/chrome/browser/ui/android/webid/account_selection_view_android.cc
index 8f4f802..5ff41a47 100644
--- a/chrome/browser/ui/android/webid/account_selection_view_android.cc
+++ b/chrome/browser/ui/android/webid/account_selection_view_android.cc
@@ -142,7 +142,7 @@
     float device_scale_factor) {
   ScopedJavaLocalRef<jclass> account_clazz = base::android::GetClass(
       env, "org/chromium/chrome/browser/ui/android/webid/data/Account");
-  ScopedJavaLocalRef<jobjectArray> array(
+  auto array = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(accounts.size(), account_clazz.obj(), nullptr));
 
   base::android::CheckException(env);
@@ -193,7 +193,7 @@
   ScopedJavaLocalRef<jclass> identity_provider_clazz = base::android::GetClass(
       env,
       "org/chromium/chrome/browser/ui/android/webid/data/IdentityProviderData");
-  ScopedJavaLocalRef<jobjectArray> array(
+  auto array = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(identity_providers_map.size(),
                                identity_provider_clazz.obj(), nullptr));
 
diff --git a/chrome/browser/ui/android/webid/internal/BUILD.gn b/chrome/browser/ui/android/webid/internal/BUILD.gn
index f3a7e3c..d67cd8c 100644
--- a/chrome/browser/ui/android/webid/internal/BUILD.gn
+++ b/chrome/browser/ui/android/webid/internal/BUILD.gn
@@ -166,6 +166,7 @@
     "//chrome/browser/ui/android/webid:public_java",
     "//chrome/browser/webid:java",
     "//chrome/test/android:chrome_java_integration_test_support",
+    "//chrome/test/android:chrome_java_transit",
     "//components/browser_ui/bottomsheet/android:java",
     "//components/browser_ui/bottomsheet/android/test:java",
     "//components/image_fetcher:java",
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTestBase.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTestBase.java
index 71a2a80..b6f838e0 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTestBase.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionIntegrationTestBase.java
@@ -26,7 +26,9 @@
 import org.chromium.chrome.browser.ui.android.webid.data.IdentityCredentialTokenError;
 import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderData;
 import org.chromium.chrome.browser.ui.android.webid.data.IdentityProviderMetadata;
-import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.transit.ChromeTransitTestRules;
+import org.chromium.chrome.test.transit.FreshCtaTransitTestRule;
+import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
@@ -76,8 +78,10 @@
     @Mock AccountSelectionComponent.Delegate mMockBridge;
 
     @Rule
-    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+    public FreshCtaTransitTestRule mActivityTestRule =
+            ChromeTransitTestRules.freshChromeTabbedActivityRule();
 
+    WebPageStation mPage;
     BottomSheetController mBottomSheetController;
 
     String mTestUrlTermsOfService;
@@ -96,7 +100,7 @@
     @Before
     public void setUp() throws InterruptedException {
         MockitoAnnotations.initMocks(this);
-        mActivityTestRule.startMainActivityOnBlankPage();
+        mPage = mActivityTestRule.startOnBlankPage();
 
         mTestUrlTermsOfService =
                 mActivityTestRule.getTestServer().getURL("/chrome/test/data/title1.html");
diff --git a/chrome/browser/ui/ash/shelf/BUILD.gn b/chrome/browser/ui/ash/shelf/BUILD.gn
index 4fcea5c2..163ade0 100644
--- a/chrome/browser/ui/ash/shelf/BUILD.gn
+++ b/chrome/browser/ui/ash/shelf/BUILD.gn
@@ -109,7 +109,6 @@
     "//chrome/browser/ash/system_web_apps",
     "//chrome/browser/chromeos/extensions/login_screen/login/cleanup",
     "//chrome/browser/extensions",
-    "//chrome/browser/image_decoder",
     "//chrome/browser/prefs",
     "//chrome/browser/prefs:util",
     "//chrome/browser/profiles:profile",
diff --git a/chrome/browser/ui/ash/shelf/DEPS b/chrome/browser/ui/ash/shelf/DEPS
index 9daa40b..7c930b9 100644
--- a/chrome/browser/ui/ash/shelf/DEPS
+++ b/chrome/browser/ui/ash/shelf/DEPS
@@ -51,7 +51,6 @@
   "+chrome/browser/extensions/launch_util.h",
   "+chrome/browser/extensions/menu_manager.h",
   "+chrome/browser/extensions/test_extension_system.h",
-  "+chrome/browser/image_decoder",
   "+chrome/browser/media/router",
   "+chrome/browser/prefs",
   "+chrome/browser/profiles",
diff --git a/chrome/browser/ui/ash/shelf/arc_app_window.h b/chrome/browser/ui/ash/shelf/arc_app_window.h
index 244cb525..e19b80ee 100644
--- a/chrome/browser/ui/ash/shelf/arc_app_window.h
+++ b/chrome/browser/ui/ash/shelf/arc_app_window.h
@@ -11,7 +11,6 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "base/memory/raw_ptr.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/ui/ash/shelf/app_window_base.h"
 #include "chrome/browser/ui/ash/shelf/arc_app_shelf_id.h"
 #include "components/app_icon_loader/app_icon_loader.h"
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn
index fc720d9..82d5a75 100644
--- a/chrome/browser/ui/autofill/BUILD.gn
+++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -165,6 +165,7 @@
 
   if (is_android) {
     sources += [
+      "autofill_keyboard_accessory_controller.cc",
       "autofill_keyboard_accessory_controller_impl.cc",
       "autofill_snackbar_controller_impl.cc",
     ]
@@ -172,7 +173,6 @@
       "//chrome/browser/autofill/android:jni_headers",
       "//chrome/browser/fast_checkout",
       "//chrome/browser/keyboard_accessory/android:public",
-      "//chrome/browser/password_manager/android/access_loss:public",
       "//components/android_autofill/browser:android",
       "//components/messages/android:feature_flags",
       "//components/password_manager/core/browser/features:password_features",
@@ -326,8 +326,6 @@
 
   if (is_android) {
     sources += [ "autofill_keyboard_accessory_controller_impl_test_api.h" ]
-    public_deps +=
-        [ "//chrome/browser/password_manager/android/access_loss:public" ]
   } else {
     sources += [
       "autofill_ai/mock_save_or_update_ai_data_controller.cc",
@@ -434,10 +432,7 @@
       "mock_autofill_keyboard_accessory_view.h",
       "test_autofill_keyboard_accessory_controller_autofill_client.h",
     ]
-    public_deps += [
-      "//chrome/browser/keyboard_accessory/test_utils/android",
-      "//chrome/browser/password_manager/android/access_loss:test_support",
-    ]
+    public_deps += [ "//chrome/browser/keyboard_accessory/test_utils/android" ]
   } else {
     sources += [ "test_autofill_popup_controller_autofill_client.h" ]
   }
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.cc
new file mode 100644
index 0000000..14f99af4
--- /dev/null
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.cc
@@ -0,0 +1,14 @@
+// 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 "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h"
+
+namespace autofill {
+
+AutofillKeyboardAccessoryController::RemovalConfirmationText::
+    RemovalConfirmationText() = default;
+AutofillKeyboardAccessoryController::RemovalConfirmationText::
+    ~RemovalConfirmationText() = default;
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h
index c364aaa5..70d29f3f 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller.h
@@ -5,7 +5,8 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_H_
 
-#include <memory>
+#include <string>
+#include <vector>
 
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
 
@@ -17,6 +18,16 @@
 class AutofillKeyboardAccessoryController
     : public AutofillSuggestionController {
  public:
+  struct RemovalConfirmationText {
+    RemovalConfirmationText();
+    ~RemovalConfirmationText();
+
+    std::u16string title;
+    std::u16string body;
+    std::u16string body_link;
+    std::u16string confirm_button_text;
+  };
+
   // Returns all the labels of the suggestion at the given `row` index. The
   // labels are presented as a N*M matrix, and the position of the text in the
   // matrix decides where the text will be shown on the UI. (e.g. The text
@@ -27,7 +38,7 @@
 
   // Checks if the item at `index` can be removed.
   //
-  // If removable, this populates the non-null output parameters with
+  // If removable, this populates the non-null output parameter with
   // user-facing text for a confirmation dialog (e.g., for a "Remove" or
   // "Delete" action).
   //
@@ -35,9 +46,7 @@
   // `false` otherwise.
   virtual bool GetRemovalConfirmationText(
       int index,
-      std::u16string* title,
-      std::u16string* body,
-      std::u16string* confirm_button_text) = 0;
+      RemovalConfirmationText* removal_text) = 0;
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
index d6e5de612..bc9e7dad 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.cc
@@ -18,8 +18,8 @@
 #include "base/strings/strcat.h"
 #include "base/time/time.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/autofill/ui/ui_util.h"
 #include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h"
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
@@ -44,10 +44,19 @@
 namespace {
 
 using FillingSource = ManualFillingController::FillingSource;
+using RemovalConfirmationText =
+    AutofillKeyboardAccessoryController::RemovalConfirmationText;
 
 constexpr std::u16string_view kLabelSeparator = u" ";
 constexpr size_t kMaxBulletCount = 8;
 
+constexpr std::u16string_view kHomeAddressManagementUrl =
+    u"https://myaccount.google.com/address/"
+    u"home?utm_source=chrome&utm_campaign=manage_addresses";
+constexpr std::u16string_view kWorkAddressManagementUrl =
+    u"https://myaccount.google.com/address/"
+    u"work?utm_source=chrome&utm_campaign=manage_addresses";
+
 // Creates a text label used by the keyboard accessory. For password
 // suggestions, constructs the label from the password stored in
 // `Suggestion::additional_label` and an optional signon realm stored in
@@ -80,6 +89,119 @@
   return Suggestion::Text(suggestion.labels[0][0].value);
 }
 
+std::u16string GetAccountEmail(content::WebContents* web_contents) {
+  if (!web_contents) {
+    return {};
+  }
+  const std::optional<AccountInfo> account =
+      GetPrimaryAccountInfoFromBrowserContext(
+          web_contents->GetBrowserContext());
+  return account ? base::UTF8ToUTF16(account->email) : std::u16string();
+}
+
+// Gets the text for a dialog to confirm removing an autocomplete suggestion.
+// Returns `true` if the atucomplete entry can be deleted, `false` otherwise.
+[[nodiscard]] bool GetAutocompleteRemovalText(
+    const std::u16string& value,
+    RemovalConfirmationText* removal_text) {
+  if (removal_text) {
+    removal_text->title = value;
+    removal_text->body = l10n_util::GetStringUTF16(
+        IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY);
+    removal_text->confirm_button_text =
+        l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON);
+  }
+  return true;
+}
+
+// Gets the text for a dialog to confirm removing a credit card suggestion.
+// Returns `true` if the card can be deleted, `false` otherwise.
+[[nodiscard]] bool GetCreditCardRemovalText(
+    const Suggestion::Payload& payload,
+    content::WebContents* web_contents,
+    RemovalConfirmationText* removal_text) {
+  if (!std::holds_alternative<Suggestion::Guid>(payload)) {
+    return false;
+  }
+  PersonalDataManager* pdm = PersonalDataManagerFactory::GetForBrowserContext(
+      web_contents->GetBrowserContext());
+  const CreditCard* credit_card =
+      pdm->payments_data_manager().GetCreditCardByGUID(
+          std::get<Suggestion::Guid>(payload).value());
+  if (!credit_card || !CreditCard::IsLocalCard(credit_card)) {
+    return false;
+  }
+
+  if (removal_text) {
+    removal_text->title = credit_card->CardNameAndLastFourDigits();
+    removal_text->body = l10n_util::GetStringUTF16(
+        IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY);
+    removal_text->confirm_button_text =
+        l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON);
+  }
+  return true;
+}
+
+// Gets the text for a dialog to confirm removing an address suggestion.
+// The text varies based on the profile type (e.g., local vs. Home/Work).
+// Returns `true` if the address profile can be deleted, `false` otherwise.
+[[nodiscard]] bool GetAddressRemovalText(
+    const Suggestion::Payload& payload,
+    const std::u16string& value,
+    content::WebContents* web_contents,
+    RemovalConfirmationText* removal_text) {
+  if (!std::holds_alternative<Suggestion::AutofillProfilePayload>(payload)) {
+    return false;
+  }
+  PersonalDataManager* pdm = PersonalDataManagerFactory::GetForBrowserContext(
+      web_contents->GetBrowserContext());
+  const AutofillProfile* profile = pdm->address_data_manager().GetProfileByGUID(
+      std::get<Suggestion::AutofillProfilePayload>(payload).guid.value());
+  if (!profile) {
+    return false;
+  }
+
+  if (removal_text) {
+    switch (profile->record_type()) {
+      case AutofillProfile::RecordType::kLocalOrSyncable:
+      case AutofillProfile::RecordType::kAccount:
+        if (std::u16string street_address =
+                profile->GetRawInfo(ADDRESS_HOME_CITY);
+            !street_address.empty()) {
+          removal_text->title = std::move(street_address);
+        } else {
+          removal_text->title = value;
+        }
+        removal_text->body = l10n_util::GetStringUTF16(
+            IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY);
+        removal_text->confirm_button_text =
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON);
+        break;
+      case AutofillProfile::RecordType::kAccountHome:
+        removal_text->title = l10n_util::GetStringUTF16(
+            IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_TITLE);
+        removal_text->body = l10n_util::GetStringFUTF16(
+            IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_BODY,
+            GetAccountEmail(web_contents));
+        removal_text->body_link = kHomeAddressManagementUrl;
+        removal_text->confirm_button_text =
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON);
+        break;
+      case AutofillProfile::RecordType::kAccountWork:
+        removal_text->title = l10n_util::GetStringUTF16(
+            IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_TITLE);
+        removal_text->body = l10n_util::GetStringFUTF16(
+            IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_BODY,
+            GetAccountEmail(web_contents));
+        removal_text->body_link = kWorkAddressManagementUrl;
+        removal_text->confirm_button_text =
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON);
+        break;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 // static
@@ -273,27 +395,6 @@
 
   delegate_->DidAcceptSuggestion(
       suggestion, AutofillSuggestionDelegate::SuggestionMetadata{.row = index});
-
-  if (suggestion.type != SuggestionType::kPasswordEntry) {
-    // Returning early because the code below triggers the UI which is shown
-    // after accepting passwords.
-    return;
-  }
-
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
-  if (!access_loss_warning_bridge_) {
-    access_loss_warning_bridge_ =
-        std::make_unique<PasswordAccessLossWarningBridgeImpl>();
-  }
-  if (profile && access_loss_warning_bridge_->ShouldShowAccessLossNoticeSheet(
-                     profile->GetPrefs(), /*called_at_startup=*/false)) {
-    access_loss_warning_bridge_->MaybeShowAccessLossNoticeSheet(
-        profile->GetPrefs(), web_contents_->GetTopLevelNativeWindow(), profile,
-        /*called_at_startup=*/false,
-        password_manager_android_util::PasswordAccessLossWarningTriggers::
-            kKeyboardAcessoryBar);
-  }
 }
 
 bool AutofillKeyboardAccessoryControllerImpl::RemoveSuggestion(
@@ -301,15 +402,14 @@
     AutofillMetrics::SingleEntryRemovalMethod removal_method) {
   CHECK_EQ(removal_method,
            AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory);
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirm_button_text;
-  if (!GetRemovalConfirmationText(index, &title, &body, &confirm_button_text)) {
+  RemovalConfirmationText removal_text;
+  if (!GetRemovalConfirmationText(index, &removal_text)) {
     return false;
   }
 
   view_->ConfirmDeletion(
-      title, body, confirm_button_text,
+      removal_text.title, removal_text.body, removal_text.body_link,
+      removal_text.confirm_button_text,
       base::BindOnce(
           &AutofillKeyboardAccessoryControllerImpl::OnDeletionDialogClosed,
           GetWeakPtr(), index));
@@ -516,87 +616,26 @@
 
 bool AutofillKeyboardAccessoryControllerImpl::GetRemovalConfirmationText(
     int index,
-    std::u16string* title,
-    std::u16string* body,
-    std::u16string* confirm_button_text) {
+    RemovalConfirmationText* removal_text) {
   CHECK_LT(base::checked_cast<size_t>(index), suggestions_.size());
   const std::u16string& value = suggestions_[index].main_text.value;
   const SuggestionType type = suggestions_[index].type;
   const Suggestion::Payload& payload = suggestions_[index].payload;
 
   if (type == SuggestionType::kAutocompleteEntry) {
-    if (title) {
-      title->assign(value);
-    }
-    if (body) {
-      body->assign(l10n_util::GetStringUTF16(
-          IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY));
-    }
-    if (confirm_button_text) {
-      confirm_button_text->assign(
-          l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
-    }
-    return true;
+    return GetAutocompleteRemovalText(value, removal_text);
   }
 
-  if (type != SuggestionType::kAddressEntry &&
-      type != SuggestionType::kCreditCardEntry) {
-    return false;
-  }
-  PersonalDataManager* pdm = PersonalDataManagerFactory::GetForBrowserContext(
-      web_contents_->GetBrowserContext());
-
-  if (std::holds_alternative<Suggestion::Guid>(payload)) {
-    if (const CreditCard* credit_card =
-            pdm->payments_data_manager().GetCreditCardByGUID(
-                std::get<Suggestion::Guid>(payload).value())) {
-      if (!CreditCard::IsLocalCard(credit_card)) {
-        return false;
-      }
-      if (title) {
-        title->assign(credit_card->CardNameAndLastFourDigits());
-      }
-      if (body) {
-        body->assign(l10n_util::GetStringUTF16(
-            IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY));
-      }
-      if (confirm_button_text) {
-        confirm_button_text->assign(
-            l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
-      }
-      return true;
-    }
-    return false;
+  if (type == SuggestionType::kCreditCardEntry) {
+    return GetCreditCardRemovalText(payload, web_contents_.get(), removal_text);
   }
 
-  if (std::holds_alternative<Suggestion::AutofillProfilePayload>(payload)) {
-    if (const AutofillProfile* profile =
-            pdm->address_data_manager().GetProfileByGUID(
-                std::get<Suggestion::AutofillProfilePayload>(payload)
-                    .guid.value())) {
-      if (title) {
-        std::u16string street_address = profile->GetRawInfo(ADDRESS_HOME_CITY);
-        if (!street_address.empty()) {
-          title->swap(street_address);
-        } else {
-          title->assign(value);
-        }
-      }
-      if (body) {
-        body->assign(l10n_util::GetStringUTF16(
-            IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
-      }
-      if (confirm_button_text) {
-        confirm_button_text->assign(
-            l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
-      }
-
-      return true;
-    }
-    return false;
+  if (type == SuggestionType::kAddressEntry) {
+    return GetAddressRemovalText(payload, value, web_contents_.get(),
+                                 removal_text);
   }
 
-  return false;  // The ID was valid. The entry may have been deleted in a race.
+  return false;
 }
 
 void AutofillKeyboardAccessoryControllerImpl::
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
index 6fc2289c..902ce20 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h
@@ -26,7 +26,6 @@
 }  // namespace content
 
 class Profile;
-class PasswordAccessLossWarningBridge;
 
 namespace autofill {
 
@@ -84,10 +83,9 @@
   // AutofillKeyboardAccessoryController:
   std::vector<std::vector<Suggestion::Text>> GetSuggestionLabelsAt(
       int row) const override;
-  bool GetRemovalConfirmationText(int index,
-                                  std::u16string* title,
-                                  std::u16string* body,
-                                  std::u16string* confirm_button_text) override;
+  bool GetRemovalConfirmationText(
+      int index,
+      RemovalConfirmationText* removal_text) override;
 
   base::WeakPtr<AutofillKeyboardAccessoryControllerImpl> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
@@ -158,10 +156,6 @@
   // `FillingProduct` is.
   FillingProduct suggestions_filling_product_ = FillingProduct::kNone;
 
-  // Bridge used to show the data loss warning (expected to be shown after
-  // filling user's credentials).
-  std::unique_ptr<PasswordAccessLossWarningBridge> access_loss_warning_bridge_;
-
   base::WeakPtrFactory<AutofillKeyboardAccessoryControllerImpl>
       self_deletion_weak_ptr_factory_{this};
 
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h
index e7ca5b1b..f8011a6 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_TEST_API_H_
 #define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_KEYBOARD_ACCESSORY_CONTROLLER_IMPL_TEST_API_H_
 
-#include "chrome/browser/password_manager/android/access_loss/password_access_loss_warning_bridge.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
@@ -40,15 +39,6 @@
     return controller_->view_.get();
   }
 
-  void SetAccessLossWarningBridge(
-      std::unique_ptr<PasswordAccessLossWarningBridge> bridge) {
-    controller_->access_loss_warning_bridge_ = std::move(bridge);
-  }
-
-  PasswordAccessLossWarningBridge* access_loss_warning_bridge() {
-    return controller_->access_loss_warning_bridge_.get();
-  }
-
  private:
   const raw_ref<AutofillKeyboardAccessoryControllerImpl> controller_;
 };
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
index 5c2bcb9..0a6c5b3 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_unittest.cc
@@ -9,9 +9,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/time/time.h"
+#include "chrome/browser/autofill/ui/ui_util.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h"
 #include "chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h"
 #include "components/autofill/core/browser/data_manager/addresses/address_data_manager.h"
+#include "components/autofill/core/browser/data_model/addresses/autofill_profile_test_api.h"
 #include "components/autofill/core/browser/suggestions/suggestion_hiding_reason.h"
 #include "components/autofill/core/browser/suggestions/suggestion_type.h"
 #include "components/strings/grit/components_strings.h"
@@ -30,6 +32,9 @@
 using ::testing::MockFunction;
 using ::testing::Return;
 
+using RemovalConfirmationText =
+    AutofillKeyboardAccessoryController::RemovalConfirmationText;
+
 std::vector<Suggestion> CreateSuggestionsWithUndoOrClearEntry(
     size_t clear_form_offset) {
   auto create_pw_suggestion = [](std::string_view password,
@@ -53,8 +58,7 @@
     : public AutofillSuggestionControllerTestBase<
           TestAutofillKeyboardAccessoryControllerAutofillClient<>> {
  protected:
-  AutofillProfile ShowAutofillProfileSuggestion() {
-    AutofillProfile complete_profile = test::GetFullProfile();
+  void ShowAutofillProfileSuggestion(AutofillProfile complete_profile) {
     personal_data().address_data_manager().AddProfile(complete_profile);
     ShowSuggestions(
         manager(),
@@ -62,7 +66,6 @@
             SuggestionType::kAddressEntry, u"Complete autofill profile",
             Suggestion::AutofillProfilePayload(
                 Suggestion::Guid(complete_profile.guid())))});
-    return complete_profile;
   }
 
   CreditCard ShowLocalCardSuggestion() {
@@ -149,62 +152,55 @@
 
 TEST_F(AutofillKeyboardAccessoryControllerImplTest,
        GetRemovalConfirmationText_UnrelatedSuggestionType) {
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
   ShowSuggestions(
       manager(),
       {Suggestion(u"Entry", SuggestionType::kAddressFieldByFieldFilling)});
 
   EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
+      0, nullptr));
 }
 
 TEST_F(AutofillKeyboardAccessoryControllerImplTest,
        GetRemovalConfirmationText_InvalidUniqueId) {
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
   ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
                                  SuggestionType::kAddressFieldByFieldFilling,
                                  u"Entry", Suggestion::Guid("1111"))});
 
   EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
+      0, nullptr));
 }
 
 TEST_F(AutofillKeyboardAccessoryControllerImplTest,
        GetRemovalConfirmationText_Autocomplete) {
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
+  RemovalConfirmationText confirmation_text;
   ShowSuggestions(manager(), {Suggestion(u"Autocomplete entry",
                                          SuggestionType::kAutocompleteEntry)});
 
   EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
-  EXPECT_EQ(title, u"Autocomplete entry");
-  EXPECT_EQ(body,
+      0, &confirmation_text));
+  EXPECT_EQ(confirmation_text.title, u"Autocomplete entry");
+  EXPECT_EQ(confirmation_text.body,
             l10n_util::GetStringUTF16(
                 IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY));
-  EXPECT_EQ(confirmation_button_text,
+  EXPECT_TRUE(confirmation_text.body_link.empty());
+
+  EXPECT_EQ(confirmation_text.confirm_button_text,
             l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
 }
 
 TEST_F(AutofillKeyboardAccessoryControllerImplTest,
        GetRemovalConfirmationText_LocalCreditCard) {
   CreditCard local_card = ShowLocalCardSuggestion();
+  RemovalConfirmationText confirmation_text;
 
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
   EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
-  EXPECT_EQ(title, local_card.CardNameAndLastFourDigits());
-  EXPECT_EQ(body,
+      0, &confirmation_text));
+  EXPECT_EQ(confirmation_text.title, local_card.CardNameAndLastFourDigits());
+  EXPECT_EQ(confirmation_text.body,
             l10n_util::GetStringUTF16(
                 IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY));
-  EXPECT_EQ(confirmation_button_text,
+  EXPECT_TRUE(confirmation_text.body_link.empty());
+  EXPECT_EQ(confirmation_text.confirm_button_text,
             l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
 }
 
@@ -213,44 +209,96 @@
   CreditCard server_card = test::GetMaskedServerCard();
   personal_data().test_payments_data_manager().AddServerCreditCard(server_card);
 
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
   ShowSuggestions(manager(),
                   {test::CreateAutofillSuggestion(
                       SuggestionType::kCreditCardEntry, u"Server credit card",
                       Suggestion::Guid(server_card.guid()))});
 
   EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
+      0, nullptr));
 }
 
 TEST_F(AutofillKeyboardAccessoryControllerImplTest,
        GetRemovalConfirmationText_CompleteAutofillProfile) {
-  AutofillProfile complete_profile = ShowAutofillProfileSuggestion();
+  AutofillProfile complete_profile = test::GetFullProfile();
+  ShowAutofillProfileSuggestion(complete_profile);
+  RemovalConfirmationText confirmation_text;
 
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
   EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
-  EXPECT_EQ(title, complete_profile.GetRawInfo(ADDRESS_HOME_CITY));
-  EXPECT_EQ(body,
+      0, &confirmation_text));
+  EXPECT_EQ(confirmation_text.title,
+            complete_profile.GetRawInfo(ADDRESS_HOME_CITY));
+  EXPECT_EQ(confirmation_text.body,
             l10n_util::GetStringUTF16(
                 IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
-  EXPECT_EQ(confirmation_button_text,
+  EXPECT_TRUE(confirmation_text.body_link.empty());
+  EXPECT_EQ(confirmation_text.confirm_button_text,
             l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
 }
 
 TEST_F(AutofillKeyboardAccessoryControllerImplTest,
+       GetRemovalConfirmationText_CompleteAutofillHomeProfile) {
+  AutofillProfile complete_profile = test::GetFullProfile();
+  test_api(complete_profile)
+      .set_record_type(AutofillProfile::RecordType::kAccountHome);
+  ShowAutofillProfileSuggestion(complete_profile);
+  RemovalConfirmationText confirmation_text;
+
+  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &confirmation_text));
+  EXPECT_EQ(
+      confirmation_text.title,
+      l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_TITLE));
+
+  std::u16string email =
+      base::UTF8ToUTF16(GetPrimaryAccountInfoFromBrowserContext(
+                            web_contents()->GetBrowserContext())
+                            ->email);
+  EXPECT_EQ(confirmation_text.body,
+            l10n_util::GetStringFUTF16(
+                IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_BODY,
+                email));
+  EXPECT_FALSE(confirmation_text.body_link.empty());
+  EXPECT_EQ(confirmation_text.confirm_button_text,
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON));
+}
+
+TEST_F(AutofillKeyboardAccessoryControllerImplTest,
+       GetRemovalConfirmationText_CompleteAutofillWorkProfile) {
+  AutofillProfile complete_profile = test::GetFullProfile();
+  test_api(complete_profile)
+      .set_record_type(AutofillProfile::RecordType::kAccountWork);
+  ShowAutofillProfileSuggestion(complete_profile);
+  RemovalConfirmationText confirmation_text;
+
+  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &confirmation_text));
+  EXPECT_EQ(
+      confirmation_text.title,
+      l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_TITLE));
+
+  std::u16string email =
+      base::UTF8ToUTF16(GetPrimaryAccountInfoFromBrowserContext(
+                            web_contents()->GetBrowserContext())
+                            ->email);
+  EXPECT_EQ(confirmation_text.body,
+            l10n_util::GetStringFUTF16(
+                IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_BODY,
+                email));
+  EXPECT_FALSE(confirmation_text.body_link.empty());
+  EXPECT_EQ(confirmation_text.confirm_button_text,
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON));
+}
+
+TEST_F(AutofillKeyboardAccessoryControllerImplTest,
        GetRemovalConfirmationText_AutofillProfile_EmptyCity) {
   AutofillProfile profile = test::GetFullProfile();
   profile.ClearFields({ADDRESS_HOME_CITY});
   personal_data().address_data_manager().AddProfile(profile);
+  RemovalConfirmationText confirmation_text;
 
-  std::u16string title;
-  std::u16string body;
-  std::u16string confirmation_button_text;
   ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
                                  SuggestionType::kAddressEntry,
                                  u"Autofill profile without city",
@@ -258,12 +306,13 @@
                                      Suggestion::Guid(profile.guid())))});
 
   EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body, &confirmation_button_text));
-  EXPECT_EQ(title, u"Autofill profile without city");
-  EXPECT_EQ(body,
+      0, &confirmation_text));
+  EXPECT_EQ(confirmation_text.title, u"Autofill profile without city");
+  EXPECT_EQ(confirmation_text.body,
             l10n_util::GetStringUTF16(
                 IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
-  EXPECT_EQ(confirmation_button_text,
+  EXPECT_TRUE(confirmation_text.body_link.empty());
+  EXPECT_EQ(confirmation_text.confirm_button_text,
             l10n_util::GetStringUTF16(IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON));
 }
 
@@ -277,7 +326,7 @@
   ASSERT_TRUE(client().popup_view());
 
   EXPECT_CALL(*client().popup_view(), ConfirmDeletion)
-      .WillOnce(base::test::RunOnceCallback<3>(/*confirmed=*/true));
+      .WillOnce(base::test::RunOnceCallback<4>(/*confirmed=*/true));
   EXPECT_CALL(manager().external_delegate(), RemoveSuggestion(suggestion))
       .WillOnce(Return(true));
   EXPECT_CALL(*client().popup_view(),
@@ -288,63 +337,6 @@
       AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory));
 }
 
-TEST_F(AutofillKeyboardAccessoryControllerImplTest,
-       AcceptPwdSuggestionInvokesAccessLossWarningAndroid) {
-  ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
-  EXPECT_CALL(*client().access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*client().access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet(
-                  profile()->GetPrefs(), _, profile(),
-                  /*called_at_startup=*/false,
-                  password_manager_android_util::
-                      PasswordAccessLossWarningTriggers::kKeyboardAcessoryBar));
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
-TEST_F(AutofillKeyboardAccessoryControllerImplTest,
-       AcceptUsernameSuggestionInvokesAccessLossWarningAndroid) {
-  ShowSuggestions(manager(), {SuggestionType::kPasswordEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
-  EXPECT_CALL(*client().access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*client().access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet(
-                  profile()->GetPrefs(), _, profile(),
-                  /*called_at_startup=*/false,
-                  password_manager_android_util::
-                      PasswordAccessLossWarningTriggers::kKeyboardAcessoryBar));
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
-TEST_F(AutofillKeyboardAccessoryControllerImplTest,
-       AcceptAddressNoPwdAccessLossWarningAndroid) {
-  ShowSuggestions(manager(), {SuggestionType::kAddressEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
-  EXPECT_CALL(*client().access_loss_warning_bridge(),
-              ShouldShowAccessLossNoticeSheet(profile()->GetPrefs(),
-                                              /*called_at_startup=*/false))
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*client().access_loss_warning_bridge(),
-              MaybeShowAccessLossNoticeSheet)
-      .Times(0);
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
 // When a suggestion is accepted, the popup is hidden inside
 // `delegate->DidAcceptSuggestion()`. On Android, some code is still being
 // executed after hiding. This test makes sure no use-after-free, null pointer
diff --git a/chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h b/chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h
index da89dd5..89ac0f5 100644
--- a/chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h
+++ b/chrome/browser/ui/autofill/autofill_keyboard_accessory_view.h
@@ -44,6 +44,7 @@
   virtual void ConfirmDeletion(
       const std::u16string& confirmation_title,
       const std::u16string& confirmation_body,
+      const std::u16string& confirmation_body_link,
       const std::u16string& confirm_button_text,
       base::OnceCallback<void(bool)> deletion_callback) = 0;
 };
diff --git a/chrome/browser/ui/autofill/mock_autofill_keyboard_accessory_view.h b/chrome/browser/ui/autofill/mock_autofill_keyboard_accessory_view.h
index 586a740..1818d84 100644
--- a/chrome/browser/ui/autofill/mock_autofill_keyboard_accessory_view.h
+++ b/chrome/browser/ui/autofill/mock_autofill_keyboard_accessory_view.h
@@ -27,6 +27,7 @@
               (const std::u16string&,
                const std::u16string&,
                const std::u16string&,
+               const std::u16string&,
                base::OnceCallback<void(bool)>),
               (override));
 };
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
index b5a2fb7..14e7339 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
@@ -1001,7 +1001,26 @@
     save_and_fill_dialog_controller_ =
         std::make_unique<SaveAndFillDialogControllerImpl>();
   }
-  save_and_fill_dialog_controller_->ShowDialog(
+  save_and_fill_dialog_controller_->ShowLocalDialog(
+      base::BindOnce(&CreateAndShowSaveAndFillDialog,
+                     save_and_fill_dialog_controller_->GetWeakPtr(),
+                     web_contents()),
+      std::move(callback));
+#else
+  NOTIMPLEMENTED();
+#endif  // !BUILDFLAG(IS_ANDROID)
+}
+
+void ChromePaymentsAutofillClient::ShowCreditCardUploadSaveAndFillDialog(
+    const LegalMessageLines& legal_message_lines,
+    CardSaveAndFillDialogCallback callback) {
+#if !BUILDFLAG(IS_ANDROID)
+  if (!save_and_fill_dialog_controller_) {
+    save_and_fill_dialog_controller_ =
+        std::make_unique<SaveAndFillDialogControllerImpl>();
+  }
+  save_and_fill_dialog_controller_->ShowUploadDialog(
+      std::move(legal_message_lines),
       base::BindOnce(&CreateAndShowSaveAndFillDialog,
                      save_and_fill_dialog_controller_->GetWeakPtr(),
                      web_contents()),
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h
index ccfbcb3..aeb62cc 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.h
@@ -213,6 +213,9 @@
   PaymentsDataManager& GetPaymentsDataManager() final;
   void ShowCreditCardLocalSaveAndFillDialog(
       CardSaveAndFillDialogCallback callback) override;
+  void ShowCreditCardUploadSaveAndFillDialog(
+      const LegalMessageLines& legal_message_lines,
+      CardSaveAndFillDialogCallback callback) override;
   payments::SaveAndFillManager* GetSaveAndFillManager() override;
   void ShowSelectBnplIssuerDialog(
       std::vector<BnplIssuerContext> bnpl_issuer_context,
diff --git a/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h b/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h
index d016369..98eac77 100644
--- a/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h
+++ b/chrome/browser/ui/autofill/test_autofill_keyboard_accessory_controller_autofill_client.h
@@ -9,7 +9,6 @@
 #include <memory>
 
 #include "base/test/mock_callback.h"
-#include "chrome/browser/password_manager/android/access_loss/mock_password_access_loss_warning_bridge.h"
 #include "chrome/browser/ui/autofill/autofill_keyboard_accessory_controller_impl_test_api.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller_test_base.h"
@@ -50,9 +49,6 @@
               ->GetWeakPtr();
       test_api(cast_popup_controller())
           .SetView(std::make_unique<MockAutofillKeyboardAccessoryView>());
-      test_api(cast_popup_controller())
-          .SetAccessLossWarningBridge(
-              std::make_unique<MockPasswordAccessLossWarningBridge>());
       manager_of_last_controller_ = manager.GetWeakPtr();
       ON_CALL(cast_popup_controller(), Hide)
           .WillByDefault(
@@ -67,14 +63,6 @@
                              : nullptr;
   }
 
-  MockPasswordAccessLossWarningBridge* access_loss_warning_bridge() {
-    return popup_controller_
-               ? static_cast<MockPasswordAccessLossWarningBridge*>(
-                     test_api(cast_popup_controller())
-                         .access_loss_warning_bridge())
-               : nullptr;
-  }
-
  private:
   void DoHide(SuggestionHidingReason reason) {
     if (popup_controller_) {
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 5850603..8180d6a 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -93,6 +93,7 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tab_dialogs.h"
 #include "chrome/browser/ui/tabs/features.h"
+#include "chrome/browser/ui/tabs/new_tab_grouping_user_data.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_service.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_service_factory.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
@@ -1003,6 +1004,10 @@
   // user-initiated commands.
   UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", NewTabTypes::NEW_TAB_COMMAND,
                             NewTabTypes::NEW_TAB_ENUM_COUNT);
+  browser->profile()->SetUserData(
+      NewTabGroupingUserData::kNewTabGroupingUserDataKey,
+      std::make_unique<NewTabGroupingUserData>(
+          browser->tab_strip_model()->GetActiveTabGroupId()));
   if (browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)) {
     return *AddAndReturnTabAt(browser, GURL(), -1, true);
   }
diff --git a/chrome/browser/ui/browser_list.h b/chrome/browser/ui/browser_list.h
index 3b37392d..cb8c41a 100644
--- a/chrome/browser/ui/browser_list.h
+++ b/chrome/browser/ui/browser_list.h
@@ -64,7 +64,8 @@
   BrowserList(const BrowserList&) = delete;
   BrowserList& operator=(const BrowserList&) = delete;
 
-  // Returns the last active browser for this list.
+  // TODO(crbug.com/431671448): Prefer `GetLastActiveBrowserWindowInterface()`,
+  // this method is being deprecated.
   Browser* GetLastActive() const;
 
   const_iterator begin() const { return browsers_.begin(); }
diff --git a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
index 767a8d2f..c8f4264 100644
--- a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
@@ -5,13 +5,18 @@
 #include "chrome/browser/ui/browser_navigator_browsertest.h"
 
 #include "ash/constants/ash_switches.h"
+#include "ash/public/cpp/multi_user_window_manager.h"
+#include "ash/public/cpp/new_window_delegate.h"
 #include "ash/wm/window_pin_util.h"
 #include "base/command_line.h"
 #include "chrome/browser/ash/login/chrome_restart_request.h"
+#include "chrome/browser/ash/login/test/device_state_mixin.h"
+#include "chrome/browser/ash/login/test/login_manager_mixin.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
-#include "chrome/browser/ui/ash/multi_user/test_multi_user_window_manager.h"
+#include "chrome/browser/ui/ash/session/session_controller_client_impl.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -19,8 +24,16 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/mixin_based_in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
 #include "components/account_id/account_id.h"
+#include "components/account_id/account_id_literal.h"
+#include "components/session_manager/core/session.h"
+#include "components/session_manager/core/session_manager.h"
+#include "components/signin/public/identity_manager/account_managed_status_finder.h"
+#include "components/user_manager/user_manager_pref_names.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "ui/aura/window.h"
@@ -151,59 +164,151 @@
       incognito_browser->tab_strip_model()->GetActiveWebContents()->GetURL());
 }
 
+class BrowserNavigatorMultiUserTestChromeOS
+    : public InProcessBrowserTestMixinHostSupport<
+          BrowserNavigatorTestChromeOS> {
+ public:
+  static constexpr inline auto kPrimaryAccountId =
+      AccountId::Literal::FromUserEmailGaiaId("primary@test",
+                                              GaiaId::Literal("12345"));
+  static constexpr inline auto kSecondaryAccountId =
+      AccountId::Literal::FromUserEmailGaiaId("secondary@test",
+                                              GaiaId::Literal("67890"));
+
+  BrowserNavigatorMultiUserTestChromeOS() = default;
+  ~BrowserNavigatorMultiUserTestChromeOS() override = default;
+
+  void SetUp() override {
+    set_exit_when_last_browser_closes(false);
+    signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
+        "test");
+    InProcessBrowserTestMixinHostSupport<BrowserNavigatorTestChromeOS>::SetUp();
+  }
+
+  void TearDown() override {
+    InProcessBrowserTestMixinHostSupport<
+        BrowserNavigatorTestChromeOS>::TearDown();
+    signin::AccountManagedStatusFinder::SetNonEnterpriseDomainForTesting(
+        nullptr);
+  }
+
+  void LogIn(const AccountId& account_id) {
+    // If there's already a session, i.e. if this is multi user sign in,
+    // first, launch user selection flow.
+    if (auto* primary_session =
+            session_manager::SessionManager::Get()->GetPrimarySession()) {
+      // Mark the acknowledge for the multi-user sign-in.
+      user_manager::User* primary_user =
+          user_manager::UserManager::Get()->FindUserAndModify(
+              primary_session->account_id());
+      primary_user->GetProfilePrefs()->SetBoolean(
+          user_manager::prefs::kMultiProfileNeverShowIntro, true);
+      SessionControllerClientImpl::Get()->ShowMultiProfileLogin();
+    }
+
+    login_manager_mixin_.LoginWithDefaultContext(
+        ash::LoginManagerMixin::TestUserInfo(account_id));
+  }
+
+ private:
+  ash::DeviceStateMixin device_state_{
+      &mixin_host_,
+      ash::DeviceStateMixin::State::OOBE_COMPLETED_PERMANENTLY_UNOWNED};
+  ash::LoginManagerMixin login_manager_mixin_{
+      &mixin_host_,
+      {ash::LoginManagerMixin::TestUserInfo(kPrimaryAccountId),
+       ash::LoginManagerMixin::TestUserInfo(kSecondaryAccountId)}};
+};
+
 // Test that in multi user environments a newly created browser gets created
 // on the same desktop as the browser is shown on.
-IN_PROC_BROWSER_TEST_F(BrowserGuestSessionNavigatorTest,
+IN_PROC_BROWSER_TEST_F(BrowserNavigatorMultiUserTestChromeOS,
                        Browser_Gets_Created_On_Visiting_Desktop) {
+  // Set up primary user.
+  LogIn(kPrimaryAccountId);
+  Profile* primary_user_profile = Profile::FromBrowserContext(
+      ash::BrowserContextHelper::Get()->GetBrowserContextByAccountId(
+          kPrimaryAccountId));
+  ASSERT_TRUE(primary_user_profile);
+
+  // Create a browser window with the primary user.
+  ash::NewWindowDelegate::GetInstance()->NewWindow(
+      /*incognito=*/false, /*should_trigger_session_restore=*/false);
+
+  ASSERT_EQ(1u, chrome::GetTotalBrowserCount());
+  Browser* browser = chrome::FindBrowserWithProfile(primary_user_profile);
+  ASSERT_TRUE(browser);
+
+  // Start multi-user sign-in.
+  LogIn(kSecondaryAccountId);
+
+  auto* window_manager = MultiUserWindowManagerHelper::GetWindowManager();
+
   // Test 1: Test that a browser created from a visiting browser will be on the
   // same visiting desktop.
   {
-    const AccountId desktop_account_id(
-        AccountId::FromUserEmail("desktop_user_id@fake.com"));
-    TestMultiUserWindowManager* window_manager =
-        TestMultiUserWindowManager::Create(browser(), desktop_account_id);
+    // Make sure the current active user is the secondary.
+    ASSERT_EQ(session_manager::SessionManager::Get()
+                  ->GetActiveSession()
+                  ->account_id(),
+              kSecondaryAccountId);
 
+    // Teleport the primary user's browser window to the secondary user's
+    // desktop.
+    window_manager->ShowWindowForUser(
+        browser->window()->GetNativeWindow()->GetToplevelWindow(),
+        kSecondaryAccountId);
     EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
 
-    // Navigate to the settings page.
-    NavigateParams params(MakeNavigateParams(browser()));
+    // Navigate to the settings page from the primary user's browser.
+    NavigateParams params(MakeNavigateParams(browser));
     params.disposition = WindowOpenDisposition::NEW_POPUP;
     params.url = GURL("chrome://settings");
     params.window_action = NavigateParams::SHOW_WINDOW;
     params.path_behavior = NavigateParams::IGNORE_AND_NAVIGATE;
-    params.browser = browser();
-    Navigate(&params);
-
+    params.browser = browser;
+    auto navigated = Navigate(&params);
     EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
 
-    aura::Window* created_window = window_manager->created_window();
+    // Verify the created window is shown on the secondary user's desktop.
+    aura::Window* created_window =
+        navigated->GetWebContents()->GetTopLevelNativeWindow();
     ASSERT_TRUE(created_window);
     EXPECT_TRUE(
         MultiUserWindowManagerHelper::GetInstance()->IsWindowOnDesktopOfUser(
-            created_window, desktop_account_id));
+            created_window, kSecondaryAccountId));
   }
+
   // Test 2: Test that a window which is not visiting does not cause an owner
   // assignment of a newly created browser.
   {
-    const AccountId browser_owner =
-        multi_user_util::GetAccountIdFromProfile(browser()->profile());
-    TestMultiUserWindowManager* window_manager =
-        TestMultiUserWindowManager::Create(browser(), browser_owner);
+    // Move the browser window back to the primary user's desktop.
+    window_manager->ShowWindowForUser(
+        browser->window()->GetNativeWindow()->GetToplevelWindow(),
+        kPrimaryAccountId);
+    // Teleporting the window also triggers to switch the active session.
+    ASSERT_EQ(session_manager::SessionManager::Get()
+                  ->GetActiveSession()
+                  ->account_id(),
+              kPrimaryAccountId);
 
     // Navigate to the settings page.
-    NavigateParams params(MakeNavigateParams(browser()));
+    NavigateParams params(MakeNavigateParams(browser));
     params.disposition = WindowOpenDisposition::NEW_POPUP;
     params.url = GURL("chrome://settings");
     params.window_action = NavigateParams::SHOW_WINDOW;
     params.path_behavior = NavigateParams::IGNORE_AND_NAVIGATE;
-    params.browser = browser();
-    Navigate(&params);
-
+    params.browser = browser;
+    auto navigated = Navigate(&params);
     EXPECT_EQ(3u, chrome::GetTotalBrowserCount());
 
-    // The ShowWindowForUser should not have been called since the window is
-    // already on the correct desktop.
-    ASSERT_FALSE(window_manager->created_window());
+    // The created window should be at the primary user's desktop now.
+    aura::Window* created_window =
+        navigated->GetWebContents()->GetTopLevelNativeWindow();
+    ASSERT_TRUE(created_window);
+    EXPECT_TRUE(
+        MultiUserWindowManagerHelper::GetInstance()->IsWindowOnDesktopOfUser(
+            created_window, kPrimaryAccountId));
   }
 }
 
diff --git a/chrome/browser/ui/browser_window/BUILD.gn b/chrome/browser/ui/browser_window/BUILD.gn
index bb2dd13..c387a95 100644
--- a/chrome/browser/ui/browser_window/BUILD.gn
+++ b/chrome/browser/ui/browser_window/BUILD.gn
@@ -46,7 +46,10 @@
       "public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java",
       "public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTracker.java",
     ]
-    deps = [ "//build/android:build_java" ]
+    deps = [
+      "//build/android:build_java",
+      "//ui/android:ui_no_recycler_view_java",
+    ]
   }
 
   # Public Java factory
@@ -54,4 +57,19 @@
     deps = [ ":java" ]
     sources = [ "internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerFactory.java" ]
   }
+} else {
+  source_set("browser_tests") {
+    testonly = true
+    sources = [ "public/browser_window_interface_iterator_browsertest.cc" ]
+    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+    deps = [
+      ":browser_window",
+      "//base",
+      "//base/test:test_support",
+      "//chrome/browser/ui",
+      "//chrome/test:test_support",
+      "//content/test:test_support",
+      "//testing/gtest",
+    ]
+  }
 }
diff --git a/chrome/browser/ui/browser_window/internal/BUILD.gn b/chrome/browser/ui/browser_window/internal/BUILD.gn
index be417d0..f42c699 100644
--- a/chrome/browser/ui/browser_window/internal/BUILD.gn
+++ b/chrome/browser/ui/browser_window/internal/BUILD.gn
@@ -21,6 +21,7 @@
       "android/android_browser_window.cc",
       "android/browser_window_interface_iterator_android.cc",
     ]
+    deps += [ ":jni" ]
   } else {
     sources += [
       "browser_window_features.cc",
@@ -81,16 +82,41 @@
   }
 }
 
+source_set("unit_tests") {
+  testonly = true
+  sources = []
+  deps = [
+    ":internal",
+    "//testing/gtest",
+  ]
+
+  if (is_android) {
+    sources += [
+      "android/android_base_window_unittest.cc",
+      "android/android_browser_window_unittest.cc",
+    ]
+    deps += [
+      "//base",
+      "//chrome/browser/ui/browser_window/test:native_unit_test_support_java",
+      "//chrome/browser/ui/browser_window/test:native_unit_test_support_jni",
+      "//ui/base",
+    ]
+  }
+}
+
 # Android targets need to be guarded by is_android because:
 # (1) Android GNI files may assert is_android, and
 # (2) The rest of this file can be included in non-Android builds.
 if (is_android) {
   import("//build/config/android/rules.gni")
+  import("//third_party/jni_zero/jni_zero.gni")
 
   android_library("java") {
     visibility = [
       ":*",
       "//chrome/android:chrome_all_java",
+      "//chrome/browser/ui/browser_window/test:junit_test_support",
+      "//chrome/browser/ui/browser_window/test:native_unit_test_support_java",
     ]
     sources = [
       "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindow.java",
@@ -102,6 +128,35 @@
     deps = [
       "//build/android:build_java",
       "//chrome/browser/ui/browser_window:java",
+      "//third_party/androidx:androidx_annotation_annotation_java",
+      "//third_party/jni_zero:jni_zero_java",
+      "//ui/android:ui_no_recycler_view_java",
+    ]
+    srcjar_deps = [ ":jni" ]
+  }
+
+  generate_jni("jni") {
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindow.java",
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java",
+    ]
+  }
+
+  robolectric_library("junit") {
+    testonly = true
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java",
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImplUnitTest.java",
+    ]
+    deps = [
+      ":java",
+      "//base:base_junit_test_support",
+      "//build/android:build_java",
+      "//chrome/browser/ui/browser_window:java",
+      "//chrome/browser/ui/browser_window/test:junit_test_support",
+      "//third_party/junit",
+      "//third_party/mockito:mockito_java",
+      "//ui/android:ui_no_recycler_view_java",
     ]
   }
 }
diff --git a/chrome/browser/ui/browser_window/internal/android/android_base_window.cc b/chrome/browser/ui/browser_window/internal/android/android_base_window.cc
index c321a6a..188b6e8 100644
--- a/chrome/browser/ui/browser_window/internal/android/android_base_window.cc
+++ b/chrome/browser/ui/browser_window/internal/android/android_base_window.cc
@@ -4,12 +4,39 @@
 
 #include "chrome/browser/ui/browser_window/internal/android/android_base_window.h"
 
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
 #include "base/notreached.h"
+#include "chrome/browser/ui/browser_window/internal/jni/AndroidBaseWindow_jni.h"
 #include "ui/gfx/geometry/rect.h"
 
-AndroidBaseWindow::AndroidBaseWindow() = default;
+namespace {
+using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+}  // namespace
 
-AndroidBaseWindow::~AndroidBaseWindow() = default;
+// Implements Java |AndroidBaseWindow.Natives#create|.
+static jlong JNI_AndroidBaseWindow_Create(JNIEnv* env,
+                                          const JavaParamRef<jobject>& caller) {
+  return reinterpret_cast<intptr_t>(new AndroidBaseWindow(env, caller));
+}
+
+AndroidBaseWindow::AndroidBaseWindow(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& java_android_base_window) {
+  java_android_base_window_.Reset(env, java_android_base_window);
+}
+
+AndroidBaseWindow::~AndroidBaseWindow() {
+  Java_AndroidBaseWindow_clearNativePtr(AttachCurrentThread(),
+                                        java_android_base_window_);
+}
+
+void AndroidBaseWindow::Destroy(JNIEnv* env) {
+  delete this;
+}
 
 bool AndroidBaseWindow::IsActive() const {
   NOTREACHED();
diff --git a/chrome/browser/ui/browser_window/internal/android/android_base_window.h b/chrome/browser/ui/browser_window/internal/android/android_base_window.h
index 1a34a24..b0e5ab6 100644
--- a/chrome/browser/ui/browser_window/internal/android/android_base_window.h
+++ b/chrome/browser/ui/browser_window/internal/android/android_base_window.h
@@ -5,16 +5,24 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BASE_WINDOW_H_
 #define CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BASE_WINDOW_H_
 
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
 #include "ui/base/base_window.h"
 
 // Android implementation of |ui::BaseWindow|.
 class AndroidBaseWindow final : public ui::BaseWindow {
  public:
-  AndroidBaseWindow();
+  AndroidBaseWindow(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& java_android_base_window);
   AndroidBaseWindow(const AndroidBaseWindow&) = delete;
   AndroidBaseWindow& operator=(const AndroidBaseWindow&) = delete;
   ~AndroidBaseWindow();
 
+  // Implements Java |AndroidBaseWindow.Natives#destroy|.
+  void Destroy(JNIEnv* env);
+
   // Implements |ui::BaseWindow|.
   bool IsActive() const override;
   bool IsMaximized() const override;
@@ -38,6 +46,9 @@
   void FlashFrame(bool flash) override;
   ui::ZOrderLevel GetZOrderLevel() const override;
   void SetZOrderLevel(ui::ZOrderLevel order) override;
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject> java_android_base_window_;
 };
 
 #endif  // CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BASE_WINDOW_H_
diff --git a/chrome/browser/ui/browser_window/internal/android/android_base_window_unittest.cc b/chrome/browser/ui/browser_window/internal/android/android_base_window_unittest.cc
new file mode 100644
index 0000000..5d93c5dd
--- /dev/null
+++ b/chrome/browser/ui/browser_window/internal/android/android_base_window_unittest.cc
@@ -0,0 +1,76 @@
+// 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 "chrome/browser/ui/browser_window/internal/android/android_base_window.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/ui/browser_window/test/native_unit_test_support_jni/AndroidBaseWindowNativeUnitTestSupport_jni.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaGlobalRef;
+}  // namespace
+
+class AndroidBaseWindowUnitTest : public testing::Test {
+ public:
+  AndroidBaseWindowUnitTest() = default;
+  ~AndroidBaseWindowUnitTest() override = default;
+
+  void SetUp() override {
+    java_test_support_ =
+        Java_AndroidBaseWindowNativeUnitTestSupport_Constructor(
+            AttachCurrentThread());
+  }
+
+  void TearDown() override { InvokeJavaDestroy(); }
+
+  AndroidBaseWindow* InvokeJavaGetOrCreateNativePtr() const {
+    return reinterpret_cast<AndroidBaseWindow*>(
+        Java_AndroidBaseWindowNativeUnitTestSupport_invokeGetOrCreateNativePtr(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+  AndroidBaseWindow* InvokeJavaGetNativePtrForTesting() const {
+    return reinterpret_cast<AndroidBaseWindow*>(
+        Java_AndroidBaseWindowNativeUnitTestSupport_invokeGetNativePtrForTesting(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+  void InvokeJavaDestroy() const {
+    Java_AndroidBaseWindowNativeUnitTestSupport_invokeDestroy(
+        AttachCurrentThread(), java_test_support_);
+  }
+
+ private:
+  ScopedJavaGlobalRef<jobject> java_test_support_;
+};
+
+TEST_F(AndroidBaseWindowUnitTest,
+       JavaGetOrCreateNativePtrMethodReturnsSamePtr) {
+  // Arrange & Act: call Java GetOrCreateNativePtr() twice.
+  AndroidBaseWindow* ptr1 = InvokeJavaGetOrCreateNativePtr();
+  AndroidBaseWindow* ptr2 = InvokeJavaGetOrCreateNativePtr();
+
+  // Assert: the two calls should return the same non-null pointer.
+  EXPECT_NE(nullptr, ptr1);
+  EXPECT_NE(nullptr, ptr2);
+  EXPECT_EQ(ptr1, ptr2);
+}
+
+TEST_F(AndroidBaseWindowUnitTest, JavaDestroyMethodClearsPtrValueInJava) {
+  // Arrange.
+  InvokeJavaGetOrCreateNativePtr();
+
+  // Act: call Java destroy().
+  InvokeJavaDestroy();
+
+  // Assert: the native pointer on the Java side should be set to null.
+  AndroidBaseWindow* android_base_window = InvokeJavaGetNativePtrForTesting();
+  EXPECT_EQ(nullptr, android_base_window);
+}
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc b/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc
index 52a2cfb..091a8e8 100644
--- a/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc
+++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window.cc
@@ -4,13 +4,41 @@
 
 #include "chrome/browser/ui/browser_window/internal/android/android_browser_window.h"
 
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
 #include "base/notreached.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_window/internal/jni/AndroidBrowserWindow_jni.h"
 #include "ui/base/unowned_user_data/unowned_user_data_host.h"
 
-AndroidBrowserWindow::AndroidBrowserWindow() = default;
+namespace {
+using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+}  // namespace
 
-AndroidBrowserWindow::~AndroidBrowserWindow() = default;
+// Implements Java |AndroidBrowserWindow.Natives#create|.
+static jlong JNI_AndroidBrowserWindow_Create(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& caller) {
+  return reinterpret_cast<intptr_t>(new AndroidBrowserWindow(env, caller));
+}
+
+AndroidBrowserWindow::AndroidBrowserWindow(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& java_android_browser_window) {
+  java_android_browser_window_.Reset(env, java_android_browser_window);
+}
+
+AndroidBrowserWindow::~AndroidBrowserWindow() {
+  Java_AndroidBrowserWindow_clearNativePtr(AttachCurrentThread(),
+                                           java_android_browser_window_);
+}
+
+void AndroidBrowserWindow::Destroy(JNIEnv* env) {
+  delete this;
+}
 
 ui::UnownedUserDataHost& AndroidBrowserWindow::GetUnownedUserDataHost() {
   NOTREACHED();
@@ -22,7 +50,9 @@
 }
 
 ui::BaseWindow* AndroidBrowserWindow::GetWindow() {
-  NOTREACHED();
+  return reinterpret_cast<ui::BaseWindow*>(
+      Java_AndroidBrowserWindow_getOrCreateNativeBaseWindowPtr(
+          AttachCurrentThread(), java_android_browser_window_));
 }
 
 Profile* AndroidBrowserWindow::GetProfile() {
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window.h b/chrome/browser/ui/browser_window/internal/android/android_browser_window.h
index bdc455d..44c5600e 100644
--- a/chrome/browser/ui/browser_window/internal/android/android_browser_window.h
+++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window.h
@@ -5,16 +5,24 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BROWSER_WINDOW_H_
 #define CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BROWSER_WINDOW_H_
 
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 
 // Android implementation of |BrowserWindowInterface|.
 class AndroidBrowserWindow final : public BrowserWindowInterface {
  public:
-  AndroidBrowserWindow();
+  AndroidBrowserWindow(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& java_android_browser_window);
   AndroidBrowserWindow(const AndroidBrowserWindow&) = delete;
   AndroidBrowserWindow& operator=(const AndroidBrowserWindow&) = delete;
   ~AndroidBrowserWindow() override;
 
+  // Implements Java |AndroidBrowserWindow.Natives#destroy|.
+  void Destroy(JNIEnv* env);
+
   // Implements |BrowserWindowInterface|.
   ui::UnownedUserDataHost& GetUnownedUserDataHost() override;
   const ui::UnownedUserDataHost& GetUnownedUserDataHost() const override;
@@ -28,6 +36,9 @@
       const content::OpenURLParams& params,
       base::OnceCallback<void(content::NavigationHandle&)>
           navigation_handle_callback) override;
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject> java_android_browser_window_;
 };
 
 #endif  // CHROME_BROWSER_UI_BROWSER_WINDOW_INTERNAL_ANDROID_ANDROID_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc b/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc
new file mode 100644
index 0000000..89d7ee4
--- /dev/null
+++ b/chrome/browser/ui/browser_window/internal/android/android_browser_window_unittest.cc
@@ -0,0 +1,110 @@
+// 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 "chrome/browser/ui/browser_window/internal/android/android_browser_window.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/ui/browser_window/internal/android/android_base_window.h"
+#include "chrome/browser/ui/browser_window/test/native_unit_test_support_jni/AndroidBrowserWindowNativeUnitTestSupport_jni.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/base_window.h"
+
+namespace {
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaGlobalRef;
+}  // namespace
+
+class AndroidBrowserWindowUnitTest : public testing::Test {
+ public:
+  AndroidBrowserWindowUnitTest() = default;
+  ~AndroidBrowserWindowUnitTest() override = default;
+
+  void SetUp() override {
+    java_test_support_ =
+        Java_AndroidBrowserWindowNativeUnitTestSupport_Constructor(
+            AttachCurrentThread());
+  }
+
+  void TearDown() override { InvokeJavaDestroy(); }
+
+  AndroidBrowserWindow* InvokeJavaGetOrCreateNativePtr() const {
+    return reinterpret_cast<AndroidBrowserWindow*>(
+        Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetOrCreateNativePtr(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+  AndroidBaseWindow* InvokeJavaGetOrCreateNativeBaseWindowPtr() const {
+    return reinterpret_cast<AndroidBaseWindow*>(
+        Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetOrCreateNativeBaseWindowPtr(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+  AndroidBrowserWindow* InvokeJavaGetNativePtrForTesting() const {
+    return reinterpret_cast<AndroidBrowserWindow*>(
+        Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetNativePtrForTesting(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+  AndroidBaseWindow* InvokeJavaGetNativeBaseWindowPtrForTesting() const {
+    return reinterpret_cast<AndroidBaseWindow*>(
+        Java_AndroidBrowserWindowNativeUnitTestSupport_invokeGetNativeBaseWindowPtrForTesting(
+            AttachCurrentThread(), java_test_support_));
+  }
+
+  void InvokeJavaDestroy() const {
+    Java_AndroidBrowserWindowNativeUnitTestSupport_invokeDestroy(
+        AttachCurrentThread(), java_test_support_);
+  }
+
+ private:
+  ScopedJavaGlobalRef<jobject> java_test_support_;
+};
+
+TEST_F(AndroidBrowserWindowUnitTest,
+       JavaGetOrCreateNativePtrMethodReturnsSamePtr) {
+  // Arrange & Act: call Java GetOrCreateNativePtr() twice.
+  AndroidBrowserWindow* ptr1 = InvokeJavaGetOrCreateNativePtr();
+  AndroidBrowserWindow* ptr2 = InvokeJavaGetOrCreateNativePtr();
+
+  // Assert: the two calls should return the same non-null pointer.
+  EXPECT_NE(nullptr, ptr1);
+  EXPECT_NE(nullptr, ptr2);
+  EXPECT_EQ(ptr1, ptr2);
+}
+
+TEST_F(AndroidBrowserWindowUnitTest,
+       JavaDestroyMethodClearsBrowserWindowAndBaseWindowPtrValuesInJava) {
+  // Arrange.
+  InvokeJavaGetOrCreateNativePtr();
+  InvokeJavaGetOrCreateNativeBaseWindowPtr();
+
+  // Act: call Java destroy().
+  InvokeJavaDestroy();
+
+  // Assert: the native pointers on the Java side should be set to null.
+  AndroidBrowserWindow* android_browser_window =
+      InvokeJavaGetNativePtrForTesting();
+  AndroidBaseWindow* android_base_window =
+      InvokeJavaGetNativeBaseWindowPtrForTesting();
+  EXPECT_EQ(nullptr, android_browser_window);
+  EXPECT_EQ(nullptr, android_base_window);
+}
+
+TEST_F(AndroidBrowserWindowUnitTest, GetWindowReturnsAndroidBaseWindow) {
+  // Arrange.
+  AndroidBrowserWindow* android_browser_window =
+      InvokeJavaGetOrCreateNativePtr();
+
+  // Act.
+  ui::BaseWindow* base_window = android_browser_window->GetWindow();
+
+  // Assert.
+  AndroidBaseWindow* expected_base_window =
+      InvokeJavaGetNativeBaseWindowPtrForTesting();
+  EXPECT_EQ(expected_base_window, base_window);
+}
diff --git a/chrome/browser/ui/browser_window/internal/android/browser_window_interface_iterator_android.cc b/chrome/browser/ui/browser_window/internal/android/browser_window_interface_iterator_android.cc
index 04a344a..16dc1a3 100644
--- a/chrome/browser/ui/browser_window/internal/android/browser_window_interface_iterator_android.cc
+++ b/chrome/browser/ui/browser_window/internal/android/browser_window_interface_iterator_android.cc
@@ -20,3 +20,10 @@
   NOTIMPLEMENTED();
   return {};
 }
+
+BrowserWindowInterface* GetLastActiveBrowserWindowInterface() {
+  // TODO(https://crbug.com/419057482): Implement this once we have an
+  // Android variant of BrowserWindowInterface.
+  NOTIMPLEMENTED();
+  return nullptr;
+}
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindow.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindow.java
index 68aac7a..a8fd6f92 100644
--- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindow.java
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindow.java
@@ -4,6 +4,9 @@
 
 package org.chromium.chrome.browser.ui.browser_window;
 
+import org.jni_zero.CalledByNative;
+import org.jni_zero.NativeMethods;
+
 import org.chromium.build.annotations.NullMarked;
 
 /** Java class for communicating with the native {@code AndroidBaseWindow}. */
@@ -14,7 +17,57 @@
     @SuppressWarnings("UnusedVariable")
     private final ChromeAndroidTask mChromeAndroidTask;
 
+    /** Address of the native {@code AndroidBaseWindow}. */
+    private long mNativeAndroidBaseWindow;
+
     AndroidBaseWindow(ChromeAndroidTask chromeAndroidTask) {
         mChromeAndroidTask = chromeAndroidTask;
     }
+
+    /**
+     * Returns the address of the native {@code AndroidBaseWindow}.
+     *
+     * <p>If the native {@code AndroidBaseWindow} hasn't been created, this method will create it
+     * before returning its address.
+     */
+    long getOrCreateNativePtr() {
+        if (mNativeAndroidBaseWindow == 0) {
+            mNativeAndroidBaseWindow = AndroidBaseWindowJni.get().create(this);
+        }
+        return mNativeAndroidBaseWindow;
+    }
+
+    /** Destroys all objects owned by this class. */
+    void destroy() {
+        if (mNativeAndroidBaseWindow != 0) {
+            AndroidBaseWindowJni.get().destroy(mNativeAndroidBaseWindow);
+        }
+    }
+
+    @CalledByNative
+    private void clearNativePtr() {
+        mNativeAndroidBaseWindow = 0;
+    }
+
+    long getNativePtrForTesting() {
+        return mNativeAndroidBaseWindow;
+    }
+
+    @NativeMethods
+    interface Natives {
+        /**
+         * Creates a native {@code AndroidBaseWindow}.
+         *
+         * @param caller The Java object calling this method.
+         * @return The address of the native {@code AndroidBaseWindow}.
+         */
+        long create(AndroidBaseWindow caller);
+
+        /**
+         * Destroys the native {@code AndroidBaseWindow}.
+         *
+         * @param nativeAndroidBaseWindow The address of the native {@code AndroidBaseWindow}.
+         */
+        void destroy(long nativeAndroidBaseWindow);
+    }
 }
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java
index 0f103347..9ef2c198 100644
--- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindow.java
@@ -4,16 +4,84 @@
 
 package org.chromium.chrome.browser.ui.browser_window;
 
+import org.jni_zero.CalledByNative;
+import org.jni_zero.NativeMethods;
+
 import org.chromium.build.annotations.NullMarked;
 
 /** Java class for communicating with the native {@code AndroidBrowserWindow}. */
 @NullMarked
 final class AndroidBrowserWindow {
 
-    @SuppressWarnings("UnusedVariable")
     private final AndroidBaseWindow mAndroidBaseWindow;
 
+    /** Address of the native {@code AndroidBrowserWindow}. */
+    private long mNativeAndroidBrowserWindow;
+
     AndroidBrowserWindow(ChromeAndroidTask chromeAndroidTask) {
         mAndroidBaseWindow = new AndroidBaseWindow(chromeAndroidTask);
     }
+
+    /**
+     * Returns the address of the native {@code AndroidBrowserWindow}.
+     *
+     * <p>If the native {@code AndroidBrowserWindow} hasn't been created, this method will create it
+     * before returning its address.
+     */
+    long getOrCreateNativePtr() {
+        if (mNativeAndroidBrowserWindow == 0) {
+            mNativeAndroidBrowserWindow = AndroidBrowserWindowJni.get().create(this);
+        }
+        return mNativeAndroidBrowserWindow;
+    }
+
+    /**
+     * Returns the address of the native {@code AndroidBaseWindow}.
+     *
+     * @see AndroidBaseWindow#getOrCreateNativePtr()
+     */
+    @CalledByNative
+    long getOrCreateNativeBaseWindowPtr() {
+        return mAndroidBaseWindow.getOrCreateNativePtr();
+    }
+
+    /** Destroys all objects owned by this class. */
+    void destroy() {
+        mAndroidBaseWindow.destroy();
+
+        if (mNativeAndroidBrowserWindow != 0) {
+            AndroidBrowserWindowJni.get().destroy(mNativeAndroidBrowserWindow);
+        }
+    }
+
+    long getNativePtrForTesting() {
+        return mNativeAndroidBrowserWindow;
+    }
+
+    long getNativeBaseWindowPtrForTesting() {
+        return mAndroidBaseWindow.getNativePtrForTesting();
+    }
+
+    @CalledByNative
+    private void clearNativePtr() {
+        mNativeAndroidBrowserWindow = 0;
+    }
+
+    @NativeMethods
+    interface Natives {
+        /**
+         * Creates a native {@code AndroidBrowserWindow}.
+         *
+         * @param caller The Java object calling this method.
+         * @return The address of the native {@code AndroidBrowserWindow}.
+         */
+        long create(AndroidBrowserWindow caller);
+
+        /**
+         * Destroys the native {@code AndroidBrowserWindow}.
+         *
+         * @param nativeAndroidBrowserWindow The address of the native {@code AndroidBrowserWindow}.
+         */
+        void destroy(long nativeAndroidBrowserWindow);
+    }
 }
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
index 24bc29fb..fc99976 100644
--- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
@@ -4,26 +4,195 @@
 
 package org.chromium.chrome.browser.ui.browser_window;
 
-import org.chromium.build.annotations.NullMarked;
+import android.app.Activity;
 
+import androidx.annotation.GuardedBy;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.ui.base.ActivityWindowAndroid;
+
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 /** Implements {@link ChromeAndroidTask}. */
 @NullMarked
 final class ChromeAndroidTaskImpl implements ChromeAndroidTask {
 
-    @SuppressWarnings("UnusedVariable")
+    /** States of this {@link ChromeAndroidTask}. */
+    private enum State {
+        /* The Task is alive. */
+        ALIVE,
+
+        /** The Task is being destroyed, but the destruction hasn't been completed. */
+        DESTROYING,
+
+        /** The Task has been destroyed. */
+        DESTROYED,
+    }
+
+    private final AtomicReference<State> mState = new AtomicReference<>(State.ALIVE);
+
+    private final int mId;
+
     private final AndroidBrowserWindow mAndroidBrowserWindow;
 
     /**
      * Contains all {@link ChromeAndroidTaskFeature}s associated with this {@link
      * ChromeAndroidTask}.
      */
-    @SuppressWarnings("UnusedVariable")
+    @GuardedBy("mFeaturesLock")
     private final List<ChromeAndroidTaskFeature> mFeatures = new ArrayList<>();
 
-    ChromeAndroidTaskImpl() {
+    private final Object mActivityWindowAndroidLock = new Object();
+    private final Object mFeaturesLock = new Object();
+
+    /**
+     * The {@link ActivityWindowAndroid} in this Task.
+     *
+     * <p>As a {@link ChromeAndroidTask} is meant to track an Android Task, but an {@link
+     * ActivityWindowAndroid} is associated with a {@code ChromeActivity}, we keep {@link
+     * ActivityWindowAndroid} as a {@link WeakReference} to preempt memory leaks.
+     *
+     * <p>The {@link WeakReference} still needs to be explicitly cleared at the right time so {@link
+     * ChromeAndroidTask} can always get the right state of {@link ActivityWindowAndroid}.
+     *
+     * @see #clearActivityWindowAndroid()
+     */
+    @GuardedBy("mActivityWindowAndroidLock")
+    private WeakReference<ActivityWindowAndroid> mActivityWindowAndroid = new WeakReference<>(null);
+
+    private static int getTaskId(ActivityWindowAndroid activityWindowAndroid) {
+        Activity activity = activityWindowAndroid.getActivity().get();
+        assert activity != null : "ActivityWindowAndroid should have an Activity.";
+
+        return activity.getTaskId();
+    }
+
+    ChromeAndroidTaskImpl(ActivityWindowAndroid activityWindowAndroid) {
+        mId = getTaskId(activityWindowAndroid);
         mAndroidBrowserWindow = new AndroidBrowserWindow(/* chromeAndroidTask= */ this);
+        setActivityWindowAndroidInternal(activityWindowAndroid);
+    }
+
+    @Override
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    public void setActivityWindowAndroid(ActivityWindowAndroid activityWindowAndroid) {
+        setActivityWindowAndroidInternal(activityWindowAndroid);
+    }
+
+    @Override
+    public @Nullable ActivityWindowAndroid getActivityWindowAndroid() {
+        return getActivityWindowAndroidInternal(/* assertAlive= */ true);
+    }
+
+    @Override
+    public void clearActivityWindowAndroid() {
+        clearActivityWindowAndroidInternal();
+    }
+
+    @Override
+    public void addFeature(ChromeAndroidTaskFeature feature) {
+        synchronized (mFeaturesLock) {
+            assertAlive();
+            mFeatures.add(feature);
+            feature.onAddedToTask();
+        }
+    }
+
+    @Override
+    public void destroy() {
+        // Immediately change the state to "DESTROYING" to block access to public methods that
+        // should only be called when the state is "ALIVE".
+        //
+        // One case where the "DESTROYING" state is crucial:
+        //
+        // If a ChromeAndroidTaskFeature ("Feature") holds a ChromeAndroidTask ("Task") reference,
+        // the Feature could call the Task's APIs during Feature#onTaskRemoved(). Since mState won't
+        // become "DESTROYED" until after Feature#onTaskRemoved(), we need the "DESTROYING" state to
+        // prevent the Feature from accessing the Task's APIs that should only be called when mState
+        // is "ALIVE".
+        if (!mState.compareAndSet(State.ALIVE, State.DESTROYING)) {
+            return;
+        }
+
+        clearActivityWindowAndroidInternal();
+        destroyFeatures();
+
+        mAndroidBrowserWindow.destroy();
+        mState.set(State.DESTROYED);
+    }
+
+    @Override
+    public boolean isDestroyed() {
+        return mState.get() == State.DESTROYED;
+    }
+
+    /**
+     * Same as {@link #getActivityWindowAndroid()}, but skips asserting that the {@link
+     * ChromeAndroidTask} is alive.
+     *
+     * <p>This method should only be used in tests.
+     */
+    @Nullable ActivityWindowAndroid getActivityWindowAndroidForTesting() {
+        return getActivityWindowAndroidInternal(/* assertAlive= */ false);
+    }
+
+    AndroidBrowserWindow getAndroidBrowserWindowForTesting() {
+        return mAndroidBrowserWindow;
+    }
+
+    /** Returns all {@link ChromeAndroidTaskFeature}s for testing. */
+    List<ChromeAndroidTaskFeature> getAllFeaturesForTesting() {
+        synchronized (mFeaturesLock) {
+            return mFeatures;
+        }
+    }
+
+    private void setActivityWindowAndroidInternal(ActivityWindowAndroid activityWindowAndroid) {
+        synchronized (mActivityWindowAndroidLock) {
+            assertAlive();
+            assert mActivityWindowAndroid.get() == null
+                    : "This Task already has an ActivityWindowAndroid.";
+            assert mId == getTaskId(activityWindowAndroid)
+                    : "The new ActivityWindowAndroid doesn't belong to this Task.";
+
+            mActivityWindowAndroid = new WeakReference<>(activityWindowAndroid);
+        }
+    }
+
+    private @Nullable ActivityWindowAndroid getActivityWindowAndroidInternal(boolean assertAlive) {
+        synchronized (mActivityWindowAndroidLock) {
+            if (assertAlive) {
+                assertAlive();
+            }
+
+            return mActivityWindowAndroid.get();
+        }
+    }
+
+    private void clearActivityWindowAndroidInternal() {
+        synchronized (mActivityWindowAndroidLock) {
+            mActivityWindowAndroid.clear();
+        }
+    }
+
+    private void destroyFeatures() {
+        synchronized (mFeaturesLock) {
+            for (var feature : mFeatures) {
+                feature.onTaskRemoved();
+            }
+            mFeatures.clear();
+        }
+    }
+
+    private void assertAlive() {
+        assert mState.get() == State.ALIVE : "This Task is not alive.";
     }
 }
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java
new file mode 100644
index 0000000..cdca4f1
--- /dev/null
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImplUnitTest.java
@@ -0,0 +1,276 @@
+// 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.ui.browser_window;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+import java.util.Arrays;
+
+@RunWith(BaseRobolectricTestRunner.class)
+public class ChromeAndroidTaskImplUnitTest {
+
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private static final long FAKE_NATIVE_ANDROID_BROWSER_WINDOW_PTR = 42;
+
+    private final AndroidBrowserWindow.Natives mMockAndroidBrowserWindowNatives =
+            ChromeAndroidTaskUnitTestSupport.createMockAndroidBrowserWindowNatives(
+                    FAKE_NATIVE_ANDROID_BROWSER_WINDOW_PTR);
+
+    private static ChromeAndroidTaskImpl createChromeAndroidTask() {
+        return createChromeAndroidTask(/* taskId= */ 1);
+    }
+
+    private static ChromeAndroidTaskImpl createChromeAndroidTask(int taskId) {
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(taskId);
+        return new ChromeAndroidTaskImpl(activityWindowAndroid);
+    }
+
+    @Before
+    public void setUp() {
+        AndroidBrowserWindowJni.setInstanceForTesting(mMockAndroidBrowserWindowNatives);
+    }
+
+    @Test
+    public void constructor_setsActivityWindowAndroid() {
+        // Arrange.
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+
+        // Act.
+        var chromeAndroidTask = new ChromeAndroidTaskImpl(activityWindowAndroid);
+
+        // Assert.
+        assertEquals(activityWindowAndroid, chromeAndroidTask.getActivityWindowAndroid());
+    }
+
+    @Test
+    public void getId_returnsTaskId() {
+        // Arrange.
+        int taskId = 1;
+        var chromeAndroidTask = createChromeAndroidTask(taskId);
+
+        // Act & Assert.
+        assertEquals(taskId, chromeAndroidTask.getId());
+    }
+
+    @Test
+    public void setActivityWindowAndroid_refAlreadyExists_throwsException() {
+        // Arrange.
+        var activityWindowAndroid1 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var activityWindowAndroid2 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var chromeAndroidTask = new ChromeAndroidTaskImpl(activityWindowAndroid1);
+
+        // Act & Assert.
+        assertThrows(
+                AssertionError.class,
+                () -> chromeAndroidTask.setActivityWindowAndroid(activityWindowAndroid2));
+    }
+
+    @Test
+    public void setActivityWindowAndroid_previousRefCleared_setsNewRef() {
+        // Arrange.
+        var activityWindowAndroid1 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var activityWindowAndroid2 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var chromeAndroidTask = new ChromeAndroidTaskImpl(activityWindowAndroid1);
+        chromeAndroidTask.clearActivityWindowAndroid();
+
+        // Act.
+        chromeAndroidTask.setActivityWindowAndroid(activityWindowAndroid2);
+
+        // Assert.
+        assertEquals(activityWindowAndroid2, chromeAndroidTask.getActivityWindowAndroid());
+    }
+
+    @Test
+    public void
+            setActivityWindowAndroid_previousRefCleared_newRefHasDifferentTaskId_throwsException() {
+        // Arrange.
+        var activityWindowAndroid1 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var activityWindowAndroid2 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 2);
+        var chromeAndroidTask = new ChromeAndroidTaskImpl(activityWindowAndroid1);
+        chromeAndroidTask.clearActivityWindowAndroid();
+
+        // Act & Assert.
+        assertThrows(
+                AssertionError.class,
+                () -> chromeAndroidTask.setActivityWindowAndroid(activityWindowAndroid2));
+    }
+
+    @Test
+    public void setActivityWindowAndroid_calledAfterTaskDestroyed_throwsException() {
+        // Arrange.
+        int taskId = 1;
+        var chromeAndroidTask = createChromeAndroidTask(taskId);
+        chromeAndroidTask.destroy();
+
+        // Act & Assert.
+        var newActivityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(taskId);
+        assertThrows(
+                AssertionError.class,
+                () -> chromeAndroidTask.setActivityWindowAndroid(newActivityWindowAndroid));
+    }
+
+    @Test
+    public void getActivityWindowAndroid_calledAfterTaskDestroyed_throwsException() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+        chromeAndroidTask.destroy();
+
+        // Act & Assert.
+        assertThrows(AssertionError.class, () -> chromeAndroidTask.getActivityWindowAndroid());
+    }
+
+    @Test
+    public void addFeature_addsFeatureToInternalFeatureList() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+        var mockFeature1 = mock(ChromeAndroidTaskFeature.class);
+        var mockFeature2 = mock(ChromeAndroidTaskFeature.class);
+
+        // Act.
+        chromeAndroidTask.addFeature(mockFeature1);
+        chromeAndroidTask.addFeature(mockFeature2);
+
+        // Assert.
+        assertEquals(
+                chromeAndroidTask.getAllFeaturesForTesting(),
+                Arrays.asList(mockFeature1, mockFeature2));
+    }
+
+    @Test
+    public void addFeature_invokesOnAddedToTaskForFeature() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+        var mockFeature = mock(ChromeAndroidTaskFeature.class);
+
+        // Act.
+        chromeAndroidTask.addFeature(mockFeature);
+
+        // Assert.
+        verify(mockFeature, times(1)).onAddedToTask();
+    }
+
+    @Test
+    public void addFeature_calledAfterTaskDestroyed_throwsException() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+        chromeAndroidTask.destroy();
+
+        // Act & Assert.
+        var mockFeature = mock(ChromeAndroidTaskFeature.class);
+        assertThrows(AssertionError.class, () -> chromeAndroidTask.addFeature(mockFeature));
+    }
+
+    @Test
+    public void destroy_clearsActivityWindowAndroid() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+
+        // Act.
+        chromeAndroidTask.destroy();
+
+        // Assert.
+        assertNull(chromeAndroidTask.getActivityWindowAndroidForTesting());
+    }
+
+    @Test
+    public void destroy_destroysAllFeatures() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+        var mockFeature1 = mock(ChromeAndroidTaskFeature.class);
+        var mockFeature2 = mock(ChromeAndroidTaskFeature.class);
+        chromeAndroidTask.addFeature(mockFeature1);
+        chromeAndroidTask.addFeature(mockFeature2);
+
+        // Act.
+        chromeAndroidTask.destroy();
+
+        // Assert.
+        assertTrue(chromeAndroidTask.getAllFeaturesForTesting().isEmpty());
+        verify(mockFeature1, times(1)).onTaskRemoved();
+        verify(mockFeature2, times(1)).onTaskRemoved();
+    }
+
+    @Test
+    public void destroy_destroysAndroidBrowserWindow() {
+        // Arrange: create a ChromeAndroidTask and a fake native AndroidBrowserWindow pointer value.
+        var chromeAndroidTask = createChromeAndroidTask();
+        long nativeAndroidBrowserWindowPtr =
+                chromeAndroidTask.getAndroidBrowserWindowForTesting().getOrCreateNativePtr();
+        assertEquals(FAKE_NATIVE_ANDROID_BROWSER_WINDOW_PTR, nativeAndroidBrowserWindowPtr);
+
+        // Act.
+        chromeAndroidTask.destroy();
+
+        // Assert.
+        verify(mMockAndroidBrowserWindowNatives, times(1)).destroy(nativeAndroidBrowserWindowPtr);
+    }
+
+    @Test
+    public void destroy_setsStateToDestroyed() {
+        // Arrange.
+        var chromeAndroidTask = createChromeAndroidTask();
+        assertFalse(chromeAndroidTask.isDestroyed());
+
+        // Act.
+        chromeAndroidTask.destroy();
+
+        // Assert.
+        assertTrue(chromeAndroidTask.isDestroyed());
+    }
+
+    /**
+     * Verifies that {@link ChromeAndroidTask#destroy} uses the {@code DESTROYING} state to block
+     * access to APIs that should only be called when the Task is alive.
+     */
+    @Test
+    public void destroy_blocksAccessToApisThatShouldOnlyBeCalledWhenAlive() {
+        // Arrange:
+        //
+        // Set up a mock ChromeAndroidTaskFeature that calls ChromeAndroidTask#addFeature() in
+        // its onTaskRemoved() method. No feature should do this in production, but there is nothing
+        // preventing this at compile time. Besides ChromeAndroidTask#addFeature(), the feature
+        // could also call other ChromeAndroidTask APIs that require the Task state to be "ALIVE".
+        var chromeAndroidTask = createChromeAndroidTask();
+        var mockFeature = mock(ChromeAndroidTaskFeature.class);
+        doAnswer(
+                        invocation -> {
+                            chromeAndroidTask.addFeature(mockFeature);
+                            return null;
+                        })
+                .when(mockFeature)
+                .onTaskRemoved();
+        chromeAndroidTask.addFeature(mockFeature);
+
+        // Act & Assert.
+        assertThrows(AssertionError.class, () -> chromeAndroidTask.destroy());
+    }
+}
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImpl.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImpl.java
index 2d6a50f..a21e3def 100644
--- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImpl.java
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImpl.java
@@ -4,10 +4,14 @@
 
 package org.chromium.chrome.browser.ui.browser_window;
 
+import android.app.Activity;
 import android.util.ArrayMap;
 
+import androidx.annotation.GuardedBy;
+
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
+import org.chromium.ui.base.ActivityWindowAndroid;
 
 import java.util.Map;
 
@@ -18,9 +22,11 @@
     private static @Nullable ChromeAndroidTaskTrackerImpl sInstance;
 
     /** Maps {@link ChromeAndroidTask} IDs to their instances. */
-    @SuppressWarnings("UnusedVariable")
+    @GuardedBy("mTasksLock")
     private final Map<Integer, ChromeAndroidTask> mTasks = new ArrayMap<>();
 
+    private final Object mTasksLock = new Object();
+
     static ChromeAndroidTaskTrackerImpl getInstance() {
         if (sInstance == null) {
             sInstance = new ChromeAndroidTaskTrackerImpl();
@@ -29,4 +35,64 @@
     }
 
     private ChromeAndroidTaskTrackerImpl() {}
+
+    @Override
+    public ChromeAndroidTask obtainTask(ActivityWindowAndroid activityWindowAndroid) {
+        int taskId = getTaskId(activityWindowAndroid);
+
+        synchronized (mTasksLock) {
+            var existingTask = mTasks.get(taskId);
+            if (existingTask != null) {
+                existingTask.setActivityWindowAndroid(activityWindowAndroid);
+                return existingTask;
+            }
+
+            var newTask = new ChromeAndroidTaskImpl(activityWindowAndroid);
+            mTasks.put(taskId, newTask);
+            return newTask;
+        }
+    }
+
+    @Override
+    @Nullable
+    public ChromeAndroidTask get(int taskId) {
+        synchronized (mTasksLock) {
+            return mTasks.get(taskId);
+        }
+    }
+
+    @Override
+    public void remove(int taskId) {
+        ChromeAndroidTask taskRemoved;
+
+        synchronized (mTasksLock) {
+            taskRemoved = mTasks.remove(taskId);
+        }
+
+        if (taskRemoved != null) {
+            taskRemoved.destroy();
+        }
+    }
+
+    /**
+     * Removes all {@link ChromeAndroidTask}s.
+     *
+     * <p>As this class is a singleton, we need to clear all {@link ChromeAndroidTask}s after each
+     * test.
+     *
+     * <p>This method must be called on the UI thread.
+     */
+    public void removeAllForTesting() {
+        synchronized (mTasksLock) {
+            mTasks.forEach((taskId, task) -> task.destroy());
+            mTasks.clear();
+        }
+    }
+
+    private static int getTaskId(ActivityWindowAndroid activityWindowAndroid) {
+        Activity activity = activityWindowAndroid.getActivity().get();
+        assert activity != null : "ActivityWindowAndroid should have an Activity.";
+
+        return activity.getTaskId();
+    }
 }
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImplUnitTest.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImplUnitTest.java
new file mode 100644
index 0000000..7253ace
--- /dev/null
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTrackerImplUnitTest.java
@@ -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.
+
+package org.chromium.chrome.browser.ui.browser_window;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.build.annotations.NullMarked;
+
+@NullMarked
+@RunWith(BaseRobolectricTestRunner.class)
+public class ChromeAndroidTaskTrackerImplUnitTest {
+
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private final ChromeAndroidTaskTrackerImpl mChromeAndroidTaskTracker =
+            ChromeAndroidTaskTrackerImpl.getInstance();
+
+    @After
+    public void tearDown() {
+        mChromeAndroidTaskTracker.removeAllForTesting();
+    }
+
+    @Test
+    public void obtainTask_activityWindowAndroidBelongsToNewTask_createsNewTask() {
+        // Arrange.
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+
+        // Act.
+        var chromeAndroidTask = mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid);
+
+        // Assert.
+        assertEquals(1, chromeAndroidTask.getId());
+        assertEquals(activityWindowAndroid, chromeAndroidTask.getActivityWindowAndroid());
+    }
+
+    @Test
+    public void obtainTask_activityWindowAndroidBelongsToExistingTask_reusesExistingTask() {
+        // Arrange.
+        // (1) Create a new task.
+        int taskId = 1;
+        var activityWindowAndroid1 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(taskId);
+        var chromeAndroidTask1 = mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid1);
+
+        // (2) Clear the ActivityWindowAndroid from the task.
+        // This simulates the case where ChromeActivity is killed in the background, but the Task
+        // (window) is still alive.
+        chromeAndroidTask1.clearActivityWindowAndroid();
+
+        // (3) Create another ActivityWindowAndroid that belongs to the same Task.
+        // This can happen when ChromeActivity is recreated, e.g. after ChromeActivity is killed by
+        // OS in the background, and the user later brings it back to foreground.
+        var activityWindowAndroid2 =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(taskId);
+
+        // Act.
+        var chromeAndroidTask2 = mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid2);
+
+        // Assert.
+        assertEquals(chromeAndroidTask1, chromeAndroidTask2);
+        assertEquals(taskId, chromeAndroidTask2.getId());
+        assertEquals(activityWindowAndroid2, chromeAndroidTask2.getActivityWindowAndroid());
+    }
+
+    @Test
+    public void get_taskExists_returnsTask() {
+        // Arrange.
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var chromeAndroidTask = mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid);
+
+        // Act & Assert.
+        assertEquals(chromeAndroidTask, mChromeAndroidTaskTracker.get(/* taskId= */ 1));
+    }
+
+    @Test
+    public void get_taskDoesNotExist_returnsNull() {
+        // Arrange.
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid);
+
+        // Act & Assert.
+        assertEquals(null, mChromeAndroidTaskTracker.get(/* taskId= */ 2));
+    }
+
+    @Test
+    public void remove_taskExists_destroysAndRemovesTask() {
+        // Arrange.
+        int taskId = 1;
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(taskId);
+        var chromeAndroidTask = mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid);
+
+        // Act.
+        mChromeAndroidTaskTracker.remove(taskId);
+
+        // Assert.
+        assertTrue(chromeAndroidTask.isDestroyed());
+        assertEquals(null, mChromeAndroidTaskTracker.get(taskId));
+    }
+
+    @Test
+    public void remove_taskDoesNotExist_noOp() {
+        // Arrange.
+        var activityWindowAndroid =
+                ChromeAndroidTaskUnitTestSupport.createMockActivityWindowAndroid(/* taskId= */ 1);
+        var chromeAndroidTask = mChromeAndroidTaskTracker.obtainTask(activityWindowAndroid);
+
+        // Act.
+        mChromeAndroidTaskTracker.remove(/* taskId= */ 2);
+
+        // Assert.
+        assertFalse(chromeAndroidTask.isDestroyed());
+        assertEquals(chromeAndroidTask, mChromeAndroidTaskTracker.get(/* taskId= */ 1));
+    }
+}
diff --git a/chrome/browser/ui/browser_window/internal/browser_window_interface_iterator_non_android.cc b/chrome/browser/ui/browser_window/internal/browser_window_interface_iterator_non_android.cc
index c1071632..a31ee94 100644
--- a/chrome/browser/ui/browser_window/internal/browser_window_interface_iterator_non_android.cc
+++ b/chrome/browser/ui/browser_window/internal/browser_window_interface_iterator_non_android.cc
@@ -20,3 +20,10 @@
       BrowserList::GetInstance()->begin_browsers_ordered_by_activation(),
       BrowserList::GetInstance()->end_browsers_ordered_by_activation());
 }
+
+BrowserWindowInterface* GetLastActiveBrowserWindowInterface() {
+  // TODO(crbug.com/431671448): This is implemented in terms of BrowserList to
+  // ensure it stays in sync with other BrowserList APIs during migration. It
+  // can be implemented directly once clients are migrated off of BrowserList.
+  return BrowserList::GetInstance()->GetLastActive();
+}
diff --git a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java
index 8c4159e1..ac0ab30 100644
--- a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java
+++ b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTask.java
@@ -5,6 +5,8 @@
 package org.chromium.chrome.browser.ui.browser_window;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.ui.base.ActivityWindowAndroid;
 
 /**
  * Represents an Android window containing Chrome.
@@ -38,4 +40,61 @@
  * </ul>
  */
 @NullMarked
-public interface ChromeAndroidTask {}
+public interface ChromeAndroidTask {
+
+    /**
+     * Returns the ID of this {@link ChromeAndroidTask}, which is the same as defined by {@link
+     * android.app.TaskInfo#taskId}.
+     */
+    int getId();
+
+    /**
+     * Sets the current {@link ActivityWindowAndroid} in this Task.
+     *
+     * <p>As a {@link ChromeAndroidTask} is meant to track an Android Task, but an {@link
+     * ActivityWindowAndroid} is associated with a {@code ChromeActivity}, this method is needed to
+     * support the difference in their lifecycles.
+     *
+     * <p>We assume there is at most one {@link ActivityWindowAndroid} associated with a {@link
+     * ChromeAndroidTask} at any time. If this method is called when this {@link ChromeAndroidTask}
+     * already has an {@link ActivityWindowAndroid}, an {@link AssertionError} will occur.
+     *
+     * @see #clearActivityWindowAndroid()
+     */
+    void setActivityWindowAndroid(ActivityWindowAndroid activityWindowAndroid);
+
+    /**
+     * Returns the current {@link ActivityWindowAndroid} in this Task, or {@code null} if there is
+     * none.
+     */
+    @Nullable ActivityWindowAndroid getActivityWindowAndroid();
+
+    /**
+     * Clears the current {@link ActivityWindowAndroid} in this Task.
+     *
+     * <p>This method should be called when the current {@link ActivityWindowAndroid} is about to be
+     * destroyed.
+     *
+     * @see #setActivityWindowAndroid(ActivityWindowAndroid)
+     */
+    void clearActivityWindowAndroid();
+
+    /**
+     * Adds a {@link ChromeAndroidTaskFeature} to this {@link ChromeAndroidTask}.
+     *
+     * <p>This method is the start of the {@link ChromeAndroidTaskFeature}'s lifecycle, and {@link
+     * ChromeAndroidTaskFeature#onAddedToTask} will be invoked.
+     */
+    void addFeature(ChromeAndroidTaskFeature feature);
+
+    /**
+     * Destroys all objects owned by this {@link ChromeAndroidTask}, including all {@link
+     * ChromeAndroidTaskFeature}s.
+     *
+     * @see #addFeature(ChromeAndroidTaskFeature)
+     */
+    void destroy();
+
+    /** Returns whether this {@link ChromeAndroidTask} has been destroyed. */
+    boolean isDestroyed();
+}
diff --git a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java
index 1ad0ce8..d136ecd 100644
--- a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java
+++ b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java
@@ -8,4 +8,26 @@
 
 /** Represents a Chrome feature whose lifecycle should be in sync with {@link ChromeAndroidTask}. */
 @NullMarked
-public interface ChromeAndroidTaskFeature {}
+public interface ChromeAndroidTaskFeature {
+
+    /**
+     * Called by a {@link ChromeAndroidTask} when this feature is added to it.
+     *
+     * <p>This is the start of the feature's lifecycle. Usually a feature would initialize objects
+     * it owns in this method.
+     *
+     * @see ChromeAndroidTask#addFeature(ChromeAndroidTaskFeature)
+     */
+    void onAddedToTask();
+
+    /**
+     * Called by a {@link ChromeAndroidTask} when the Task is removed.
+     *
+     * <p>This is the end of the feature's lifecycle. A feature should destroy all objects it owns
+     * in this method.
+     *
+     * @see ChromeAndroidTask#destroy()
+     * @see ChromeAndroidTaskTracker#remove(int)
+     */
+    void onTaskRemoved();
+}
diff --git a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTracker.java b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTracker.java
index c12b6dfa..5802b4a6 100644
--- a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTracker.java
+++ b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskTracker.java
@@ -5,7 +5,47 @@
 package org.chromium.chrome.browser.ui.browser_window;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
+import org.chromium.ui.base.ActivityWindowAndroid;
 
-/** Tracks {@link ChromeAndroidTask}s. */
+/**
+ * Tracks {@link ChromeAndroidTask}s.
+ *
+ * <p>The implementation of this interface should be a singleton that maintains an internal
+ * collection of all {@link ChromeAndroidTask}s.
+ */
 @NullMarked
-public interface ChromeAndroidTaskTracker {}
+public interface ChromeAndroidTaskTracker {
+
+    /**
+     * Returns a {@link ChromeAndroidTask} with the same Task ID as that of the given {@link
+     * ActivityWindowAndroid}'s {@code Activity}.
+     *
+     * <p>This method is usually called when a {@code ChromeActivity} is created, which is also when
+     * we start caring about Tasks (windows).
+     *
+     * <p>As a {@link ChromeAndroidTask} is meant to track an Android Task, but an {@link
+     * ActivityWindowAndroid} is associated with a {@code ChromeActivity}, it's possible that when
+     * this method is called, a {@link ChromeAndroidTask} already exists, in which case the existing
+     * {@link ChromeAndroidTask} will be returned.
+     *
+     * <p>Otherwise, this method will create a new {@link ChromeAndroidTask}, add it to the internal
+     * collection, and return it.
+     */
+    ChromeAndroidTask obtainTask(ActivityWindowAndroid activityWindowAndroid);
+
+    /**
+     * Returns the {@link ChromeAndroidTask} with the given {@code taskId}.
+     *
+     * @param taskId Same as defined by {@link android.app.TaskInfo#taskId}.
+     */
+    @Nullable ChromeAndroidTask get(int taskId);
+
+    /**
+     * Removes from the internal collection the {@link ChromeAndroidTask} with the given {@code
+     * taskId}, and destroys all objects owned by it (via {@link ChromeAndroidTask#destroy()}).
+     *
+     * @param taskId Same as defined by {@link android.app.TaskInfo#taskId}.
+     */
+    void remove(int taskId);
+}
diff --git a/chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h b/chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h
index c08e26b..82186fe 100644
--- a/chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h
+++ b/chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h
@@ -20,4 +20,8 @@
 std::vector<BrowserWindowInterface*>
 GetBrowserWindowInterfacesOrderedByActivation();
 
+// Returns the last active browser window interface. This can be nullptr if
+// there are no browser windows.
+BrowserWindowInterface* GetLastActiveBrowserWindowInterface();
+
 #endif  // CHROME_BROWSER_UI_BROWSER_WINDOW_PUBLIC_BROWSER_WINDOW_INTERFACE_ITERATOR_H_
diff --git a/chrome/browser/ui/browser_window/public/browser_window_interface_iterator_browsertest.cc b/chrome/browser/ui/browser_window/public/browser_window_interface_iterator_browsertest.cc
new file mode 100644
index 0000000..02de2d5
--- /dev/null
+++ b/chrome/browser/ui/browser_window/public/browser_window_interface_iterator_browsertest.cc
@@ -0,0 +1,51 @@
+// 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 "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
+
+#include "base/test/run_until.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using BrowserWindowInterfaceIteratorBrowserTest = InProcessBrowserTest;
+
+// Test that GetLastActiveBrowserWindowInterface returns the most recently
+// activated browser.
+// TODO(crbug.com/431671448): Disable test on Linux until passing.
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_GetLastActiveBrowserWindowInterface_ReturnsLastActive \
+  DISABLED_GetLastActiveBrowserWindowInterface_ReturnsLastActive
+#else
+#define MAYBE_GetLastActiveBrowserWindowInterface_ReturnsLastActive \
+  GetLastActiveBrowserWindowInterface_ReturnsLastActive
+#endif
+IN_PROC_BROWSER_TEST_F(
+    BrowserWindowInterfaceIteratorBrowserTest,
+    MAYBE_GetLastActiveBrowserWindowInterface_ReturnsLastActive) {
+  // Start with the default browser created by the test framework.
+  Browser* const browser1 = browser();
+
+  // Verify initial state - the default browser should be the last active.
+  EXPECT_EQ(GetLastActiveBrowserWindowInterface(), browser1);
+
+  // Create a second browser window.
+  Browser* const browser2 =
+      Browser::Create(Browser::CreateParams(browser()->profile(), true));
+  ASSERT_NE(browser2, nullptr);
+  browser2->window()->Show();
+
+  // Activate the second browser.
+  browser2->window()->Activate();
+  EXPECT_TRUE(base::test::RunUntil(
+      [&] { return GetLastActiveBrowserWindowInterface() == browser2; }));
+
+  // Activate the first browser again.
+  browser1->window()->Activate();
+  EXPECT_TRUE(base::test::RunUntil(
+      [&] { return GetLastActiveBrowserWindowInterface() == browser1; }));
+}
diff --git a/chrome/browser/ui/browser_window/test/BUILD.gn b/chrome/browser/ui/browser_window/test/BUILD.gn
new file mode 100644
index 0000000..7b9bcf1
--- /dev/null
+++ b/chrome/browser/ui/browser_window/test/BUILD.gn
@@ -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.
+
+# Android targets need to be guarded by is_android because:
+# (1) Android GNI files may assert is_android, and
+# (2) The rest of this file can be included in non-Android builds.
+if (is_android) {
+  import("//build/config/android/rules.gni")
+  import("//third_party/jni_zero/jni_zero.gni")
+
+  # Supports Java unit tests.
+  android_library("junit_test_support") {
+    testonly = true
+    sources = [ "android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskUnitTestSupport.java" ]
+    deps = [
+      "//build/android:build_java",
+      "//chrome/browser/ui/browser_window/internal:java",
+      "//third_party/mockito:mockito_java",
+      "//ui/android:ui_no_recycler_view_java",
+    ]
+  }
+
+  # Supports native unit tests.
+  android_library("native_unit_test_support_java") {
+    testonly = true
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindowNativeUnitTestSupport.java",
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java",
+    ]
+    deps = [
+      "//build/android:build_java",
+      "//chrome/browser/ui/browser_window:java",
+      "//chrome/browser/ui/browser_window/internal:java",
+      "//third_party/jni_zero:jni_zero_java",
+      "//third_party/mockito:mockito_java",
+    ]
+    srcjar_deps = [ ":native_unit_test_support_jni" ]
+  }
+
+  # JNI for native unit tests.
+  generate_jni("native_unit_test_support_jni") {
+    testonly = true
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindowNativeUnitTestSupport.java",
+      "android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java",
+    ]
+  }
+}
diff --git a/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindowNativeUnitTestSupport.java b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindowNativeUnitTestSupport.java
new file mode 100644
index 0000000..6622aff
--- /dev/null
+++ b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBaseWindowNativeUnitTestSupport.java
@@ -0,0 +1,48 @@
+// 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.ui.browser_window;
+
+import static org.mockito.Mockito.mock;
+
+import org.jni_zero.CalledByNative;
+
+import org.chromium.build.annotations.NullMarked;
+
+/**
+ * Supports {@code android_base_window_unittest.cc}.
+ *
+ * <p>The native unit test will use this class to:
+ *
+ * <ul>
+ *   <li>Instantiate a Java {@code AndroidBaseWindow} and its native counterpart; and
+ *   <li>Test the Java {@code AndroidBaseWindow} methods.
+ * </ul>
+ */
+@NullMarked
+final class AndroidBaseWindowNativeUnitTestSupport {
+    private final AndroidBaseWindow mAndroidBaseWindow;
+    private final ChromeAndroidTask mMockChromeAndroidTask;
+
+    @CalledByNative
+    private AndroidBaseWindowNativeUnitTestSupport() {
+        mMockChromeAndroidTask = mock(ChromeAndroidTask.class);
+        mAndroidBaseWindow = new AndroidBaseWindow(mMockChromeAndroidTask);
+    }
+
+    @CalledByNative
+    private long invokeGetOrCreateNativePtr() {
+        return mAndroidBaseWindow.getOrCreateNativePtr();
+    }
+
+    @CalledByNative
+    private long invokeGetNativePtrForTesting() {
+        return mAndroidBaseWindow.getNativePtrForTesting();
+    }
+
+    @CalledByNative
+    private void invokeDestroy() {
+        mAndroidBaseWindow.destroy();
+    }
+}
diff --git a/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java
new file mode 100644
index 0000000..5dad0486
--- /dev/null
+++ b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/AndroidBrowserWindowNativeUnitTestSupport.java
@@ -0,0 +1,58 @@
+// 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.ui.browser_window;
+
+import static org.mockito.Mockito.mock;
+
+import org.jni_zero.CalledByNative;
+
+import org.chromium.build.annotations.NullMarked;
+
+/**
+ * Supports {@code android_browser_window_unittest.cc}.
+ *
+ * <p>The native unit test will use this class to:
+ *
+ * <ul>
+ *   <li>Instantiate a Java {@code AndroidBrowserWindow} and its native counterpart; and
+ *   <li>Test the Java {@code AndroidBrowserWindow} methods.
+ * </ul>
+ */
+@NullMarked
+final class AndroidBrowserWindowNativeUnitTestSupport {
+    private final AndroidBrowserWindow mAndroidBrowserWindow;
+    private final ChromeAndroidTask mMockChromeAndroidTask;
+
+    @CalledByNative
+    private AndroidBrowserWindowNativeUnitTestSupport() {
+        mMockChromeAndroidTask = mock(ChromeAndroidTask.class);
+        mAndroidBrowserWindow = new AndroidBrowserWindow(mMockChromeAndroidTask);
+    }
+
+    @CalledByNative
+    private long invokeGetOrCreateNativePtr() {
+        return mAndroidBrowserWindow.getOrCreateNativePtr();
+    }
+
+    @CalledByNative
+    private long invokeGetOrCreateNativeBaseWindowPtr() {
+        return mAndroidBrowserWindow.getOrCreateNativeBaseWindowPtr();
+    }
+
+    @CalledByNative
+    private long invokeGetNativePtrForTesting() {
+        return mAndroidBrowserWindow.getNativePtrForTesting();
+    }
+
+    @CalledByNative
+    private long invokeGetNativeBaseWindowPtrForTesting() {
+        return mAndroidBrowserWindow.getNativeBaseWindowPtrForTesting();
+    }
+
+    @CalledByNative
+    private void invokeDestroy() {
+        mAndroidBrowserWindow.destroy();
+    }
+}
diff --git a/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskUnitTestSupport.java b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskUnitTestSupport.java
new file mode 100644
index 0000000..0005a05a
--- /dev/null
+++ b/chrome/browser/ui/browser_window/test/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskUnitTestSupport.java
@@ -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.
+
+package org.chromium.chrome.browser.ui.browser_window;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.base.ActivityWindowAndroid;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Supports Robolectric tests relevant to {@link ChromeAndroidTask}.
+ *
+ * <p>This class is package-private as it hasn't been needed outside this package.
+ */
+@NullMarked
+final class ChromeAndroidTaskUnitTestSupport {
+    private ChromeAndroidTaskUnitTestSupport() {}
+
+    /**
+     * Creates a mock {@link ActivityWindowAndroid}, which has a mock {@link Activity} with the
+     * given {@code taskId}.
+     */
+    static ActivityWindowAndroid createMockActivityWindowAndroid(int taskId) {
+        var mockActivityWindowAndroid = mock(ActivityWindowAndroid.class);
+        var mockActivity = mock(Activity.class);
+
+        when(mockActivity.getTaskId()).thenReturn(taskId);
+        when(mockActivityWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mockActivity));
+
+        return mockActivityWindowAndroid;
+    }
+
+    /**
+     * Creates a mock {@link AndroidBrowserWindow.Natives} that returns the given {@code
+     * fakeNativePtr} when {@link AndroidBrowserWindow.Natives#create()} is called.
+     */
+    static AndroidBrowserWindow.Natives createMockAndroidBrowserWindowNatives(long fakeNativePtr) {
+        var mockAndroidBrowserWindowNatives = mock(AndroidBrowserWindow.Natives.class);
+
+        when(mockAndroidBrowserWindowNatives.create(any())).thenReturn(fakeNativePtr);
+
+        return mockAndroidBrowserWindowNatives;
+    }
+}
diff --git a/chrome/browser/ui/color/tools/dump_colors.cc b/chrome/browser/ui/color/tools/dump_colors.cc
index 33bd245..6b4380d 100644
--- a/chrome/browser/ui/color/tools/dump_colors.cc
+++ b/chrome/browser/ui/color/tools/dump_colors.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 // This command-line program dumps the computed values of all color IDs to
 // stdout.
 
@@ -15,6 +10,7 @@
 #include <iostream>
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
@@ -97,7 +93,7 @@
 
   for (ui::ColorId id = ui::kUiColorsStart; id < kChromeColorsEnd; ++id) {
     std::cout << std::setfill(' ') << std::left;
-    std::cout << std::setw(longest_name) << enum_names[id];
+    std::cout << std::setw(longest_name) << UNSAFE_TODO(enum_names[id]);
     std::cout << SkColorToString(light_provider.GetColor(id));
     std::cout << SkColorToString(dark_provider.GetColor(id));
     std::cout << SkColorToString(light_high_contrast_provider.GetColor(id));
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index e473f39..091ecc6 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -1005,6 +1006,10 @@
   raw_ptr<content::WebContents> web_contents_ = nullptr;
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList feature_list_;
   web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_;
 };
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc
index 83c6c43f..7053cf0 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller.cc
@@ -1551,10 +1551,8 @@
 }
 
 void LensOverlayController::ShowOverlay() {
-  // Grab the tab contents web view and disable mouse and keyboard inputs to it.
   auto* contents_web_view = tab_->GetBrowserWindowInterface()->GetWebView();
   CHECK(contents_web_view);
-  contents_web_view->SetEnabled(false);
 
   // If the view already exists, we just need to reshow it.
   if (overlay_view_) {
@@ -1569,6 +1567,12 @@
     // The overlay needs to be focused on show to immediately begin
     // receiving key events.
     overlay_web_view_->RequestFocus();
+
+    // Disable mouse and keyboard inputs to the tab contents web view. Do this
+    // after the overlay takes focus. If it is done before, focus will move from
+    // the contents web view to another Chrome UI element before the overlay can
+    // take focus.
+    contents_web_view->SetEnabled(false);
     return;
   }
 
@@ -1603,6 +1607,12 @@
   CHECK(overlay_web_view_);
   overlay_web_view_->RequestFocus();
 
+  // Disable mouse and keyboard inputs to the tab contents web view. Do this
+  // after the overlay takes focus. If it is done before, focus will move from
+  // the contents web view to another Chrome UI element before the overlay can
+  // take focus.
+  contents_web_view->SetEnabled(false);
+
   // Listen to the render process housing out overlay.
   overlay_web_view_->GetWebContents()
       ->GetPrimaryMainFrame()
@@ -2558,6 +2568,15 @@
 }
 
 void LensOverlayController::HideOverlay() {
+  // Re-enable mouse and keyboard events to the tab contents web view, and take
+  // focus before the overlay view is hidden. If it is done after, focus will
+  // move from the overlay view to another Chrome UI element before the contents
+  // web view can take focus.
+  auto* contents_web_view = tab_->GetBrowserWindowInterface()->GetWebView();
+  CHECK(contents_web_view);
+  contents_web_view->SetEnabled(true);
+  contents_web_view->RequestFocus();
+
   // Hide the overlay view, but keep the web view attached to the overlay view
   // so that the overlay can be re-shown without creating a new web view.
   preselection_widget_anchor_->SetVisible(false);
@@ -2566,10 +2585,6 @@
 
   SetLiveBlur(false);
   HidePreselectionBubble();
-  // Re-enable mouse and keyboard events to the tab contents web view.
-  auto* contents_web_view = tab_->GetBrowserWindowInterface()->GetWebView();
-  CHECK(contents_web_view);
-  contents_web_view->SetEnabled(true);
 }
 
 void LensOverlayController::HideOverlayAndMaybeSetLivePageState() {
diff --git a/chrome/browser/ui/lens/lens_side_panel_untrusted_ui.cc b/chrome/browser/ui/lens/lens_side_panel_untrusted_ui.cc
index a269299..a394d04 100644
--- a/chrome/browser/ui/lens/lens_side_panel_untrusted_ui.cc
+++ b/chrome/browser/ui/lens/lens_side_panel_untrusted_ui.cc
@@ -114,6 +114,8 @@
   html_source->AddBoolean(
       "enableSummarizeSuggestionHint",
       lens::features::ShouldEnableSummarizeHintForContextualSuggest());
+  html_source->AddBoolean("enableAimSearchbox",
+                          lens::features::GetAimSearchboxEnabled());
 
   // Allow FrameSrc from all Google subdomains as redirects can occur.
   GURL results_side_panel_url =
diff --git a/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc
index 5c6645d..67bbc89 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller.cc
@@ -127,7 +127,7 @@
   metrics_util::LogMoveUIDismissalReason(
       dismissal_reason_,
       password_manager::features_util::ComputePasswordAccountStorageUserState(
-          profile->GetPrefs(), SyncServiceFactory::GetForProfile(profile)));
+          SyncServiceFactory::GetForProfile(profile)));
   // TODO(crbug.com/40123455): Consider recording UKM here, via:
   // metrics_recorder_->RecordUIDismissalReason(dismissal_reason_)
 }
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 32902279..a42576f 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
@@ -300,7 +300,7 @@
     if (profile) {
       user_state = password_manager::features_util::
           ComputePasswordAccountStorageUserState(
-              profile->GetPrefs(), SyncServiceFactory::GetForProfile(profile));
+              SyncServiceFactory::GetForProfile(profile));
     }
 
     // Log additional UMA for users who don't yet have any passwords saved in
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
index 35b4e08..6d050be 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller_unittest.cc
@@ -70,11 +70,10 @@
   return std::make_unique<syncer::TestSyncService>();
 }
 
-void SetupAccountPasswordStore(syncer::TestSyncService* sync_service,
-                               PrefService* pref_service) {
+void SetupAccountPasswordStore(syncer::TestSyncService* sync_service) {
   sync_service->SetSignedIn(signin::ConsentLevel::kSignin);
-  ASSERT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      pref_service, sync_service));
+  ASSERT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(sync_service));
 }
 
 }  // namespace
@@ -677,7 +676,7 @@
 
 TEST_F(SaveUpdateBubbleControllerTest,
        UpdateAccountStoreAffectsTheAccountStore) {
-  SetupAccountPasswordStore(sync_service(), prefs());
+  SetupAccountPasswordStore(sync_service());
   EXPECT_CALL(*delegate(), GetPendingPassword())
       .WillOnce(ReturnRef(pending_password()));
   std::vector<std::unique_ptr<password_manager::PasswordForm>> forms;
@@ -695,7 +694,7 @@
 
 TEST_F(SaveUpdateBubbleControllerTest,
        UpdateProfileStoreDoesnotAffectTheAccountStore) {
-  SetupAccountPasswordStore(sync_service(), prefs());
+  SetupAccountPasswordStore(sync_service());
 
   EXPECT_CALL(*delegate(), GetPendingPassword())
       .WillOnce(ReturnRef(pending_password()));
@@ -713,7 +712,7 @@
 }
 
 TEST_F(SaveUpdateBubbleControllerTest, UpdateBothStoresAffectsTheAccountStore) {
-  SetupAccountPasswordStore(sync_service(), prefs());
+  SetupAccountPasswordStore(sync_service());
   EXPECT_CALL(*delegate(), GetPendingPassword())
       .WillOnce(ReturnRef(pending_password()));
 
@@ -739,7 +738,7 @@
 
 TEST_F(SaveUpdateBubbleControllerTest,
        SaveInAccountStoreAffectsTheAccountStore) {
-  SetupAccountPasswordStore(sync_service(), prefs());
+  SetupAccountPasswordStore(sync_service());
   ON_CALL(*password_feature_manager(), IsAccountStorageEnabled)
       .WillByDefault(Return(true));
   PretendPasswordWaiting();
@@ -749,7 +748,7 @@
 
 TEST_F(SaveUpdateBubbleControllerTest,
        SaveInProfileStoreDoesntAffectTheAccountStore) {
-  SetupAccountPasswordStore(sync_service(), prefs());
+  SetupAccountPasswordStore(sync_service());
   ON_CALL(*password_feature_manager(), IsAccountStorageEnabled)
       .WillByDefault(Return(false));
   PretendPasswordWaiting();
diff --git a/chrome/browser/ui/search/BUILD.gn b/chrome/browser/ui/search/BUILD.gn
index 75c4c6a..46d96f2f 100644
--- a/chrome/browser/ui/search/BUILD.gn
+++ b/chrome/browser/ui/search/BUILD.gn
@@ -178,7 +178,6 @@
     "//content/test:test_support",
     "//ipc",
     "//ipc:message_support",
-    "//ipc:test_sink",
     "//ui/base:types",
     "//url",
   ]
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 9bc83cb..8cb551c2 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -59,12 +59,15 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/profiles/profile_ui_test_utils.h"
 #include "chrome/browser/ui/search/ntp_test_utils.h"
 #include "chrome/browser/ui/startup/launch_mode_recorder.h"
 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
 #include "chrome/browser/ui/startup/startup_types.h"
 #include "chrome/browser/ui/startup/web_app_startup_utils.h"
+#include "chrome/browser/ui/toasts/toast_controller.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/test/os_integration_test_override_impl.h"
 #include "chrome/browser/web_applications/test/web_app_test_observers.h"
@@ -77,6 +80,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -184,10 +188,13 @@
                            version_info::GetMajorVersionNumberAsInt());
 }
 
-Browser* OpenNewBrowser(Profile* profile) {
+Browser* OpenNewBrowser(Profile* profile,
+                        const std::optional<std::string>&
+                            version_string_for_testing = std::nullopt) {
   base::CommandLine dummy(base::CommandLine::NO_PROGRAM);
   StartupBrowserCreatorImpl creator(base::FilePath(), dummy,
                                     chrome::startup::IsFirstRun::kYes);
+  creator.SetCurrentChromeVersionStringForTesting(version_string_for_testing);
   ui_test_utils::BrowserChangeObserver new_browser_observer(
       nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
   creator.Launch(profile, chrome::startup::IsProcessStartup::kNo,
@@ -250,7 +257,10 @@
 
 class StartupBrowserCreatorTest : public extensions::ExtensionBrowserTest {
  protected:
-  StartupBrowserCreatorTest() = default;
+  StartupBrowserCreatorTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kNonMilestoneUpdateToast);
+  }
 
   bool SetUpUserDataDirectory() override {
     return extensions::ExtensionBrowserTest::SetUpUserDataDirectory();
@@ -304,6 +314,9 @@
     EXPECT_EQ(1U, infobar_manager->infobars().size());
 #endif  // BUILDFLAG(IS_MAC)
   }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 class OpenURLsPopupObserver : public BrowserListObserver {
@@ -604,6 +617,35 @@
       KeepAliveOrigin::WEB_APP_INTENT_PICKER));
 }
 
+IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, ShowNonMilestoneUpdateToast) {
+  // Set pref to current Chrome version.
+  PrefService* pref_service = g_browser_process->local_state();
+  pref_service->SetString(
+      prefs::kNonMilestoneUpdateToastVersion,
+      base::StringPrintf("%d.%d.%d.%d", CHROME_VERSION_MAJOR,
+                         CHROME_VERSION_MINOR, CHROME_VERSION_BUILD,
+                         CHROME_VERSION_PATCH));
+
+  // Set current chrome version to next non milestone update version.
+  std::string chrome_version_string_for_testing = base::StringPrintf(
+      "%d.%d.%d.%d", CHROME_VERSION_MAJOR, CHROME_VERSION_MINOR,
+      CHROME_VERSION_BUILD, CHROME_VERSION_PATCH + 1);
+
+  // Open a new browser and verify the toast is shown.
+  Browser* new_browser =
+      OpenNewBrowser(browser()->profile(), chrome_version_string_for_testing);
+  ASSERT_TRUE(new_browser);
+  ASSERT_TRUE(
+      new_browser->GetFeatures().toast_controller()->GetToastViewForTesting());
+
+  // Open another new browser and verify the toast is not shown.
+  Browser* new_browser2 =
+      OpenNewBrowser(browser()->profile(), chrome_version_string_for_testing);
+  ASSERT_TRUE(new_browser2);
+  ASSERT_FALSE(
+      new_browser2->GetFeatures().toast_controller()->GetToastViewForTesting());
+}
+
 namespace {
 
 enum class ChromeAppDeprecationFeatureValue {
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 4eb0e772..aafdec2 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -16,6 +16,7 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/functional/bind.h"
 #include "base/notreached.h"
+#include "base/version.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/platform_apps/install_chrome_app.h"
 #include "chrome/browser/browser_process.h"
@@ -41,14 +42,19 @@
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/startup/infobar_utils.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/startup/startup_tab.h"
 #include "chrome/browser/ui/startup/startup_tab_provider.h"
 #include "chrome/browser/ui/startup/startup_types.h"
 #include "chrome/browser/ui/tabs/shared_tab_group_version_upgrade_modal.h"
+#include "chrome/browser/ui/toasts/api/toast_id.h"
+#include "chrome/browser/ui/toasts/toast_controller.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/webui/whats_new/whats_new_util.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/custom_handlers/protocol_handler_registry.h"
@@ -134,6 +140,8 @@
       browser_creator_(browser_creator),
       is_first_run_(is_first_run) {}
 
+StartupBrowserCreatorImpl::~StartupBrowserCreatorImpl() = default;
+
 // static
 void StartupBrowserCreatorImpl::MaybeToggleFullscreen(Browser* browser) {
   // In kiosk mode, we want to always be fullscreen.
@@ -433,6 +441,14 @@
                          /*is_web_app=*/false);
 
   tab_groups::MaybeShowSharedTabGroupVersionUpgradeModal(browser);
+
+  if (base::FeatureList::IsEnabled(features::kNonMilestoneUpdateToast)) {
+    std::string current_version_string =
+        current_chrome_version_string_for_testing_.has_value()
+            ? current_chrome_version_string_for_testing_.value()
+            : CHROME_VERSION_STRING;
+    MaybeShowNonMilestoneUpdateToast(browser, current_version_string);
+  }
 }
 
 StartupBrowserCreatorImpl::DetermineStartupTabsResult::
@@ -685,6 +701,38 @@
 }
 
 // static
+void StartupBrowserCreatorImpl::MaybeShowNonMilestoneUpdateToast(
+    Browser* browser,
+    const std::string& current_version_string) {
+  if (!browser) {
+    return;
+  }
+
+  PrefService* local_state = g_browser_process->local_state();
+  std::string last_version_string =
+      local_state->GetString(prefs::kNonMilestoneUpdateToastVersion);
+
+  if (IsNonMilestoneUpdate(last_version_string, current_version_string)) {
+    browser->GetFeatures().toast_controller()->MaybeShowToast(
+        ToastParams(ToastId::kNonMilestoneUpdate));
+  }
+  local_state->SetString(prefs::kNonMilestoneUpdateToastVersion,
+                         current_version_string);
+}
+
+bool StartupBrowserCreatorImpl::IsNonMilestoneUpdate(
+    const std::string& last_version_string,
+    const std::string& current_version_string) {
+  base::Version last_version(last_version_string);
+  base::Version current_version(current_version_string);
+  if (!last_version.IsValid() || !current_version.IsValid()) {
+    return false;
+  }
+  return last_version.components()[0] == current_version.components()[0] &&
+         last_version < current_version;
+}
+
+// static
 bool StartupBrowserCreatorImpl::IsKioskModeEnabled() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kKioskMode);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.h b/chrome/browser/ui/startup/startup_browser_creator_impl.h
index 9303f837..7414153 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.h
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.h
@@ -50,7 +50,7 @@
   StartupBrowserCreatorImpl(const StartupBrowserCreatorImpl&) = delete;
   StartupBrowserCreatorImpl& operator=(const StartupBrowserCreatorImpl&) =
       delete;
-  ~StartupBrowserCreatorImpl() = default;
+  ~StartupBrowserCreatorImpl();
 
   // If command line specifies kiosk mode, or full screen mode, switch
   // to full screen.
@@ -72,6 +72,11 @@
                              chrome::startup::IsProcessStartup process_startup,
                              const std::vector<GURL>& urls);
 
+  void SetCurrentChromeVersionStringForTesting(
+      const std::optional<std::string>& version) {
+    current_chrome_version_string_for_testing_ = version;
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(BrowserTest, RestorePinnedTabs);
   FRIEND_TEST_ALL_PREFIXES(BrowserTest, AppIdSwitch);
@@ -102,6 +107,8 @@
                            DetermineStartupTabs_NewFeaturesPage);
   FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorImplTest,
                            DetermineStartupTabs_PrivacySandbox);
+  FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorImplTest,
+                           DetermineNonMilestoneUpdate);
 
   enum class LaunchResult {
     kNormally,
@@ -210,6 +217,17 @@
       bool was_mac_login_or_resume,
       bool restore_tabbed_browser);
 
+  // Show a toast if a non milestone update is detected.
+  static void MaybeShowNonMilestoneUpdateToast(
+      Browser* browser,
+      const std::string& current_version_string);
+
+  // Return whether the current version update is non milestone update.
+  // e.g, from 140.0.7297.0 to 140.0.7297.3 should return true.
+  // from 140.0.7297.0 to 141.0.7327.0 should return false.
+  static bool IsNonMilestoneUpdate(const std::string& last_version_string,
+                                   const std::string& current_version_string);
+
   // Returns whether `switches::kKioskMode` is set on the command line of
   // the current process. This is a static method to avoid accidentally reading
   // it from `command_line_`.
@@ -220,6 +238,8 @@
   raw_ptr<Profile> profile_ = nullptr;
   raw_ptr<StartupBrowserCreator> browser_creator_;
   chrome::startup::IsFirstRun is_first_run_;
+
+  std::optional<std::string> current_chrome_version_string_for_testing_;
 };
 
 #endif  // CHROME_BROWSER_UI_STARTUP_STARTUP_BROWSER_CREATOR_IMPL_H_
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc b/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc
index 4bb431f..9f2e0c4 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc
@@ -5,9 +5,11 @@
 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
 
 #include "base/command_line.h"
+#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/ui/startup/startup_tab_provider.h"
+#include "chrome/common/chrome_version.h"
 #include "chrome/common/url_constants.h"
 #include "components/signin/public/base/signin_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -568,3 +570,13 @@
   output = Creator::DetermineBrowserOpenBehavior(pref_last_and_urls, 0);
   EXPECT_EQ(Creator::BrowserOpenBehavior::NEW, output);
 }
+
+TEST_F(StartupBrowserCreatorImplTest, DetermineNonMilestoneUpdate) {
+  EXPECT_EQ(false, Creator::IsNonMilestoneUpdate("", "140.0.7297.0"));
+  EXPECT_EQ(false,
+            Creator::IsNonMilestoneUpdate("140.0.7297.0", "140.0.7297.0"));
+  EXPECT_EQ(false,
+            Creator::IsNonMilestoneUpdate("140.0.7297.0", "141.0.7327.0"));
+  EXPECT_EQ(true,
+            Creator::IsNonMilestoneUpdate("140.0.7297.0", "140.0.7297.1"));
+}
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn
index 0fe18e2..a07c510b4 100644
--- a/chrome/browser/ui/tabs/BUILD.gn
+++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -319,6 +319,7 @@
       "contents_observing_tab_feature.h",
       "features.h",
       "hover_tab_selector.h",
+      "new_tab_grouping_user_data.h",
       "pinned_tab_codec.h",
       "pinned_tab_service.h",
       "pinned_tab_service_factory.h",
@@ -326,6 +327,7 @@
       "split_tab_scrim_controller.h",
       "split_tab_scrim_delegate.h",
       "split_tab_util.h",
+      "tab_creation_metrics_controller.h",
       "tab_renderer_data.h",
       "tab_style.h",
       "tab_types.h",
@@ -380,6 +382,7 @@
       "split_tab_scrim_controller.cc",
       "split_tab_scrim_delegate.cc",
       "split_tab_util.cc",
+      "tab_creation_metrics_controller.cc",
       "tab_dialog_manager.cc",
       "tab_features.cc",
       "tab_renderer_data.cc",
@@ -546,6 +549,7 @@
       "recent_tabs_builder_test_helper.cc",
       "recent_tabs_builder_test_helper.h",
       "recent_tabs_sub_menu_model_browsertest.cc",
+      "tab_creation_metrics_controller_browsertest.cc",
       "tab_dialog_manager_browsertest.cc",
       "tab_list_bridge_browsertest.cc",
       "tab_menu_model_browsertest.cc",
diff --git a/chrome/browser/ui/tabs/alert/BUILD.gn b/chrome/browser/ui/tabs/alert/BUILD.gn
index 75d3d28..7386ef1 100644
--- a/chrome/browser/ui/tabs/alert/BUILD.gn
+++ b/chrome/browser/ui/tabs/alert/BUILD.gn
@@ -70,3 +70,32 @@
     ]
   }
 }
+
+source_set("interactive_ui_tests") {
+  testonly = true
+  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+  if (enable_glic) {
+    sources = [ "tab_alert_controller_interactive_uitest.cc" ]
+  }
+
+  deps = [
+    ":impl",
+    ":tab_alert",
+    "//chrome/browser/ui:ui_features",
+    "//chrome/browser/ui/tabs:test_support",
+    "//chrome/test:test_support",
+    "//components/tabs:test_support",
+    "//content/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  if (enable_glic) {
+    deps += [
+      "//chrome/browser/glic",
+      "//chrome/browser/glic:mojo_bindings_shared_cpp_sources",
+      "//chrome/browser/glic/test_support",
+    ]
+  }
+}
diff --git a/chrome/browser/ui/tabs/alert/tab_alert_controller.cc b/chrome/browser/ui/tabs/alert/tab_alert_controller.cc
index 092f662..d46618bf 100644
--- a/chrome/browser/ui/tabs/alert/tab_alert_controller.cc
+++ b/chrome/browser/ui/tabs/alert/tab_alert_controller.cc
@@ -79,12 +79,21 @@
 
 #if BUILDFLAG(ENABLE_GLIC)
   if (glic_keyed_service) {
+    callback_subscriptions_.push_back(
+        glic_keyed_service->AddContextAccessIndicatorStatusChangedCallback(
+            base::BindRepeating(
+                &TabAlertController::OnGlicContextAccessIndicatorStatusChanged,
+                base::Unretained(this))));
     glic::GlicSharingManager& glic_sharing_manager =
         glic_keyed_service->sharing_manager();
-    glic_sharing_status_changed_subscription_ =
+    callback_subscriptions_.emplace_back(
+        glic_sharing_manager.AddFocusedTabChangedCallback(base::BindRepeating(
+            &TabAlertController::OnGlicSharingFocusedTabChanged,
+            base::Unretained(this))));
+    callback_subscriptions_.emplace_back(
         glic_sharing_manager.AddTabPinningStatusChangedCallback(
             base::BindRepeating(&TabAlertController::OnGlicTabPinningChanged,
-                                base::Unretained(this)));
+                                base::Unretained(this))));
   }
 #endif  // BUILDFLAG(ENABLE_GLIC)
 }
@@ -206,6 +215,24 @@
   UpdateAlertState(TabAlert::VR_PRESENTING_IN_HEADSET, state);
 }
 
+#if BUILDFLAG(ENABLE_GLIC)
+void TabAlertController::OnGlicContextAccessIndicatorStatusChanged(
+    bool is_accessing) {
+  UpdateAlertState(TabAlert::GLIC_ACCESSING,
+                   GetGlicKeyedService(tab().GetBrowserWindowInterface())
+                       ->IsContextAccessIndicatorShown(tab().GetContents()));
+}
+
+void TabAlertController::OnGlicSharingFocusedTabChanged(
+    const glic::FocusedTabData& focused_tab_data) {
+  const bool is_alert_active =
+      focused_tab_data.focus() != &tab()
+          ? false
+          : GetGlicKeyedService(tab().GetBrowserWindowInterface())
+                ->IsContextAccessIndicatorShown(tab().GetContents());
+  UpdateAlertState(TabAlert::GLIC_ACCESSING, is_alert_active);
+}
+
 void TabAlertController::OnGlicTabPinningChanged(
     tabs::TabInterface* tab_interface,
     bool is_sharing) {
@@ -213,6 +240,7 @@
     UpdateAlertState(TabAlert::GLIC_SHARING, is_sharing);
   }
 }
+#endif  // BUILDFLAG(ENABLE_GLIC)
 
 void TabAlertController::UpdateAlertState(TabAlert alert, bool is_active) {
   std::optional<TabAlert> previous_alert = GetAlertToShow();
diff --git a/chrome/browser/ui/tabs/alert/tab_alert_controller.h b/chrome/browser/ui/tabs/alert/tab_alert_controller.h
index c6cacdc2..5dc54e6 100644
--- a/chrome/browser/ui/tabs/alert/tab_alert_controller.h
+++ b/chrome/browser/ui/tabs/alert/tab_alert_controller.h
@@ -23,6 +23,7 @@
 }  // namespace content
 
 namespace glic {
+class FocusedTabData;
 class GlicKeyedService;
 }  // namespace glic
 
@@ -91,9 +92,13 @@
   void OnIsContentDisplayedInHeadsetChanged(bool state) override;
 
  private:
+#if BUILDFLAG(ENABLE_GLIC)
+  void OnGlicContextAccessIndicatorStatusChanged(bool is_accessing);
+  void OnGlicSharingFocusedTabChanged(
+      const glic::FocusedTabData& focused_tab_data);
   void OnGlicTabPinningChanged(tabs::TabInterface* tab_interface,
                                bool is_sharing);
-  void ObserveAlerts();
+#endif  // BUILDFLAG(ENABLE_GLIC)
 
   // Adds `alert` to the set of already active alerts for this tab if it isn't
   // currently active. Otherwise, removes `alert` from the set and is considered
@@ -119,8 +124,8 @@
   base::ScopedObservation<vr::VrTabHelper, vr::VrTabHelper::Observer>
       vr_tab_helper_observation_{this};
 
-  // Subscription to be notified when glic sharing status has changed.
-  base::CallbackListSubscription glic_sharing_status_changed_subscription_;
+  // Subscriptions to be notified when an alert status has changed.
+  std::vector<base::CallbackListSubscription> callback_subscriptions_;
 };
 }  // namespace tabs
 
diff --git a/chrome/browser/ui/tabs/alert/tab_alert_controller_interactive_uitest.cc b/chrome/browser/ui/tabs/alert/tab_alert_controller_interactive_uitest.cc
new file mode 100644
index 0000000..865290d
--- /dev/null
+++ b/chrome/browser/ui/tabs/alert/tab_alert_controller_interactive_uitest.cc
@@ -0,0 +1,131 @@
+// 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 <optional>
+
+#include "base/callback_list.h"
+#include "base/functional/bind.h"
+#include "build/build_config.h"
+#include "chrome/browser/glic/browser_ui/glic_tab_indicator_helper.h"
+#include "chrome/browser/glic/test_support/interactive_glic_test.h"
+#include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert_controller.h"
+#include "chrome/browser/ui/tabs/public/tab_features.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/interaction/interactive_browser_test.h"
+#include "components/tabs/public/tab_interface.h"
+#include "content/public/test/browser_test.h"
+#include "ui/base/interaction/element_identifier.h"
+#include "ui/base/interaction/interactive_test.h"
+#include "ui/base/interaction/state_observer.h"
+#include "ui/views/interaction/interaction_test_util_views.h"
+#include "url/gurl.h"
+
+namespace {
+class TabAlertControllerObserver
+    : public ui::test::StateObserver<std::optional<tabs::TabAlert>> {
+ public:
+  TabAlertControllerObserver(Browser* browser, int tab_index) {
+    callback_subscription_ =
+        browser->tab_strip_model()
+            ->GetTabAtIndex(tab_index)
+            ->GetTabFeatures()
+            ->tab_alert_controller()
+            ->AddAlertToShowChangedCallback(base::BindRepeating(
+                &TabAlertControllerObserver::OnAlertToShowChanged,
+                base::Unretained(this)));
+  }
+
+  void OnAlertToShowChanged(std::optional<tabs::TabAlert> alert) {
+    OnStateObserverStateChanged(alert);
+  }
+
+  ~TabAlertControllerObserver() override = default;
+
+ private:
+  base::CallbackListSubscription callback_subscription_;
+};
+
+DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(TabAlertControllerObserver,
+                                    kTab1AlertState);
+DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(TabAlertControllerObserver,
+                                    kTab2AlertState);
+DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kFirstTabId);
+DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTabId);
+
+}  // namespace
+
+class TabAlertControllerInteractiveUiTest
+    : public glic::test::InteractiveGlicTest {
+ public:
+  TabAlertControllerInteractiveUiTest() = default;
+  ~TabAlertControllerInteractiveUiTest() override = default;
+
+  GURL GetTestUrl() const {
+    return embedded_test_server()->GetURL("/links.html");
+  }
+
+  auto LoadStartingPage(ui::ElementIdentifier id,
+                        std::optional<int> tab_index,
+                        BrowserSpecifier in_browser) {
+    return Steps(InstrumentTab(id, tab_index, in_browser),
+                 NavigateWebContents(id, GetTestUrl()));
+  }
+
+ protected:
+  const InteractiveBrowserTest::DeepQuery kMockGlicContextAccessButton = {
+      "#contextAccessIndicator"};
+};
+
+IN_PROC_BROWSER_TEST_F(TabAlertControllerInteractiveUiTest,
+                       TabAlertControllerAccessingSwitchTabs) {
+  RunTestSequence(
+      LoadStartingPage(kFirstTabId, 0, browser()),
+      AddInstrumentedTab(kSecondTabId, GetTestUrl()),
+      ObserveState(kTab1AlertState, browser(), 0),
+      ObserveState(kTab2AlertState, browser(), 1),
+      OpenGlicWindow(
+          glic::test::InteractiveGlicTest::GlicWindowMode::kAttached),
+      SelectTab(kTabStripElementId, 0),
+      ClickMockGlicElement(kMockGlicContextAccessButton),
+      WaitForState(kTab1AlertState,
+                   std::make_optional(tabs::TabAlert::GLIC_ACCESSING)),
+      SelectTab(kTabStripElementId, 1),
+      WaitForState(kTab1AlertState, std::nullopt),
+      WaitForState(kTab2AlertState,
+                   std::make_optional(tabs::TabAlert::GLIC_ACCESSING)));
+}
+
+IN_PROC_BROWSER_TEST_F(TabAlertControllerInteractiveUiTest,
+                       AlertControllerChangesOnTabMovedBetweenBrowsers) {
+#if BUILDFLAG(IS_LINUX)
+  if (views::test::InteractionTestUtilSimulatorViews::IsWayland()) {
+    GTEST_SKIP()
+        << "Programmatic window activation is not supported in the Weston "
+           "reference implementation of Wayland used by test bots.";
+  }
+#endif
+
+  Browser* const browser2 = CreateBrowser(browser()->profile());
+  RunTestSequence(
+      LoadStartingPage(kFirstTabId, 0, browser()),
+      LoadStartingPage(kSecondTabId, 0, browser2),
+      OpenGlicWindow(
+          glic::test::InteractiveGlicTest::GlicWindowMode::kDetached),
+      ActivateSurface(kBrowserViewElementId),
+      ObserveState(kTab1AlertState, browser(), 0),
+      ObserveState(kTab2AlertState, browser2, 0),
+      ClickMockGlicElement(kMockGlicContextAccessButton),
+      WaitForState(kTab1AlertState,
+                   std::make_optional(tabs::TabAlert::GLIC_ACCESSING)),
+      InContext(browser2->window()->GetElementContext(),
+                ActivateSurface(kBrowserViewElementId)),
+      WaitForState(kTab1AlertState, std::nullopt),
+      InContext(browser2->window()->GetElementContext(),
+                SelectTab(kTabStripElementId, 0)),
+      WaitForState(kTab2AlertState,
+                   std::make_optional(tabs::TabAlert::GLIC_ACCESSING)));
+}
diff --git a/chrome/browser/ui/tabs/new_tab_grouping_user_data.h b/chrome/browser/ui/tabs/new_tab_grouping_user_data.h
new file mode 100644
index 0000000..628e3536
--- /dev/null
+++ b/chrome/browser/ui/tabs/new_tab_grouping_user_data.h
@@ -0,0 +1,26 @@
+// 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 CHROME_BROWSER_UI_TABS_NEW_TAB_GROUPING_USER_DATA_H_
+#define CHROME_BROWSER_UI_TABS_NEW_TAB_GROUPING_USER_DATA_H_
+
+#include "base/supports_user_data.h"
+#include "components/tab_groups/tab_group_id.h"
+
+class NewTabGroupingUserData : public base::SupportsUserData::Data {
+ public:
+  explicit NewTabGroupingUserData(
+      std::optional<tab_groups::TabGroupId> group_id)
+      : last_active_group_id_(group_id) {}
+  std::optional<tab_groups::TabGroupId> last_active_group_id() const {
+    return last_active_group_id_;
+  }
+
+  inline static constexpr char kNewTabGroupingUserDataKey[] = "NewTabGrouping";
+
+ private:
+  std::optional<tab_groups::TabGroupId> last_active_group_id_;
+};
+
+#endif  // CHROME_BROWSER_UI_TABS_NEW_TAB_GROUPING_USER_DATA_H_
diff --git a/chrome/browser/ui/tabs/public/tab_dialog_manager.h b/chrome/browser/ui/tabs/public/tab_dialog_manager.h
index 532dfab..135586c 100644
--- a/chrome/browser/ui/tabs/public/tab_dialog_manager.h
+++ b/chrome/browser/ui/tabs/public/tab_dialog_manager.h
@@ -131,6 +131,17 @@
   // call this when the dialog's preferred size changes.
   void UpdateModalDialogBounds();
 
+  // Trigger the dialog manager to re-evaluate the dialog's visibility.
+  // Optionally pass in a `requested_visibility` which is the state the client
+  // thinks the dialog should be in, assuming the tab is visible and the window
+  // is not minimized. This will also make sure the `should_show_callback` is
+  // properly invoked and update the widget's visibility accordingly. Clients
+  // should call this when their internal state has changed which may affect the
+  // currently showing dialog's visibility. Function returns the new visibility
+  // state of the dialog.
+  bool UpdateDialogVisibility(
+      std::optional<bool> requested_visibility = std::nullopt);
+
   // Overridden from gfx::AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override;
   void AnimationEnded(const gfx::Animation* animation) override;
diff --git a/chrome/browser/ui/tabs/public/tab_features.h b/chrome/browser/ui/tabs/public/tab_features.h
index e20edfd..c7ed93d4 100644
--- a/chrome/browser/ui/tabs/public/tab_features.h
+++ b/chrome/browser/ui/tabs/public/tab_features.h
@@ -111,6 +111,7 @@
 class TabDialogManager;
 
 class InactiveWindowMouseEventController;
+class TabCreationMetricsController;
 
 // This class owns the core controllers for features that are scoped to a given
 // tab. It can be subclassed by tests to perform dependency injection.
@@ -245,6 +246,7 @@
 
   TabUIHelper* tab_ui_helper() { return tab_ui_helper_.get(); }
 
+  // actor_ui_tab_controller_ is only initialized for normal browser windows
   actor::ui::ActorUiTabController* actor_ui_tab_controller() {
     return actor_ui_tab_controller_.get();
   }
@@ -261,6 +263,10 @@
     return tab_alert_controller_.get();
   }
 
+  TabCreationMetricsController* tab_creation_metrics_controller() {
+    return tab_creation_metrics_controller_.get();
+  }
+
   // Called exactly once to initialize features.
   void Init(TabInterface& tab, Profile* profile);
 
@@ -401,6 +407,9 @@
 
   std::unique_ptr<actor::ui::ActorUiTabController> actor_ui_tab_controller_;
 
+  std::unique_ptr<TabCreationMetricsController>
+      tab_creation_metrics_controller_;
+
   // Must be the last member.
   base::WeakPtrFactory<TabFeatures> weak_factory_{this};
 };
diff --git a/chrome/browser/ui/tabs/tab_creation_metrics_controller.cc b/chrome/browser/ui/tabs/tab_creation_metrics_controller.cc
new file mode 100644
index 0000000..b459fa79
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_creation_metrics_controller.cc
@@ -0,0 +1,101 @@
+// 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 "chrome/browser/ui/tabs/tab_creation_metrics_controller.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/task_runner.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
+#include "chrome/browser/ui/tabs/new_tab_grouping_user_data.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/tab_groups/tab_group_id.h"
+#include "components/tabs/public/tab_interface.h"
+
+namespace {
+scoped_refptr<base::SequencedTaskRunner>& GetTaskRunnerOverride() {
+  static base::NoDestructor<scoped_refptr<base::SequencedTaskRunner>>
+      task_runner;
+  return *task_runner;
+}
+}  // namespace
+
+namespace tabs {
+
+void TabCreationMetricsController::SetTaskRunnerForTesting(
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
+  GetTaskRunnerOverride() = task_runner;
+}
+
+TabCreationMetricsController::TabCreationMetricsController(TabInterface* tab)
+    : tab_(tab),
+      task_runner_(GetTaskRunnerOverride()
+                       ? GetTaskRunnerOverride()
+                       : base::SequencedTaskRunner::GetCurrentDefault()) {
+  ScheduleRecordTabGroupingTransition();
+}
+
+TabCreationMetricsController::~TabCreationMetricsController() = default;
+
+void TabCreationMetricsController::ScheduleRecordTabGroupingTransition() {
+  if (!tab_->GetBrowserWindowInterface()->GetTabStripModel()) {
+    return;
+  }
+
+  std::optional<tab_groups::TabGroupId> last_active_group_id;
+  if (Profile* profile =
+          tab_->GetBrowserWindowInterface()->GetTabStripModel()->profile()) {
+    if (auto* data = profile->GetUserData(
+            NewTabGroupingUserData::kNewTabGroupingUserDataKey)) {
+      last_active_group_id =
+          static_cast<NewTabGroupingUserData*>(data)->last_active_group_id();
+    }
+  }
+
+  if (!last_active_group_id.has_value()) {
+    last_active_group_id = tab_->GetBrowserWindowInterface()
+                               ->GetTabStripModel()
+                               ->GetActiveTabGroupId();
+  }
+
+  task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&TabCreationMetricsController::RecordTabGroupingTransition,
+                     weak_factory_.GetWeakPtr(), last_active_group_id),
+      kDelay);
+}
+
+void TabCreationMetricsController::RecordTabGroupingTransition(
+    std::optional<tab_groups::TabGroupId> last_active_group_id) {
+  if (!tab_) {
+    return;
+  }
+
+  TabStripModel* tab_strip_model =
+      tab_->GetBrowserWindowInterface()->GetTabStripModel();
+  int tab_index = tab_strip_model->GetIndexOfTab(tab_);
+  std::optional<tab_groups::TabGroupId> group_id =
+      tab_->GetBrowserWindowInterface()->GetTabStripModel()->GetTabGroupForTab(
+          tab_index);
+
+  TabGroupingTransitionType type = TabGroupingTransitionType::kUninitialized;
+  if (!last_active_group_id.has_value() && !group_id.has_value()) {
+    type = TabGroupingTransitionType::kUngroupedToUngrouped;
+  } else if (!last_active_group_id.has_value() && group_id.has_value()) {
+    type = TabGroupingTransitionType::kUngroupedToGrouped;
+  } else if (last_active_group_id.has_value() && !group_id.has_value()) {
+    type = TabGroupingTransitionType::kGroupedToUngrouped;
+  } else {
+    // last_active_group_id.has_value() && group_id.has_value()
+    if (last_active_group_id.value() == group_id.value()) {
+      type = TabGroupingTransitionType::kGroupedToInPreviousGroup;
+    } else {
+      type = TabGroupingTransitionType::kGroupedToOutsidePreviousGroup;
+    }
+  }
+  base::UmaHistogramEnumeration("Tab.GroupingTransition", type);
+}
+
+}  // namespace tabs
diff --git a/chrome/browser/ui/tabs/tab_creation_metrics_controller.h b/chrome/browser/ui/tabs/tab_creation_metrics_controller.h
new file mode 100644
index 0000000..fbd301e
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_creation_metrics_controller.h
@@ -0,0 +1,86 @@
+// 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 CHROME_BROWSER_UI_TABS_TAB_CREATION_METRICS_CONTROLLER_H_
+#define CHROME_BROWSER_UI_TABS_TAB_CREATION_METRICS_CONTROLLER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+
+namespace tab_groups {
+class TabGroupId;
+}
+
+namespace tabs {
+class TabInterface;
+
+// Enumerates different types of grouping transition a tab undergoes during a
+// specific observation window. Each value includes the initial tab grouping
+// state and the ending tab grouping state.
+// LINT.IfChange(TabGroupingTransitionType)
+enum TabGroupingTransitionType {
+  // Used when the transition type is not set.
+  kUninitialized = 0,
+
+  // The tab was not in a group at the start and remains ungrouped.
+  kUngroupedToUngrouped = 1,
+
+  // The tab was not in a group at the start and joined a group.
+  kUngroupedToGrouped = 2,
+
+  // The tab was in a group at the start and became ungrouped.
+  kGroupedToUngrouped = 3,
+
+  // The tab was in a group at the start and remains in the same group.
+  kGroupedToInPreviousGroup = 4,
+
+  // The tab was in a group at the start but joined a different group.
+  kGroupedToOutsidePreviousGroup = 5,
+
+  kMaxValue = kGroupedToOutsidePreviousGroup,
+};
+// LINT.ThenChange(/tools/metrics/histograms/metadata/tab/enums.xml:TabGroupingTransitionType)
+
+// Per-tab metrics helper that records how a tab's grouping state changes
+// shortly after creation.
+//
+// When constructed, the controller gets the last active tab group if any, and
+// schedules a one-time delayed task on |task_runner_| to log how the tab's
+// grouping state changed between creation and the end of the delay (10
+// seconds).
+class TabCreationMetricsController {
+ public:
+  static constexpr base::TimeDelta kDelay = base::Seconds(10);
+
+  // Global test hook for setting task runner for the scheduled task. Must be
+  // called before TabCreationMetricsController is created. To reset to the
+  // current default task runner, pass nullptr to SetTaskRunnerForTesting().
+  static void SetTaskRunnerForTesting(
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+  explicit TabCreationMetricsController(TabInterface* tab);
+  ~TabCreationMetricsController();
+
+  TabCreationMetricsController(const TabCreationMetricsController&) = delete;
+  TabCreationMetricsController& operator=(const TabCreationMetricsController&) =
+      delete;
+
+ private:
+  // Posts a delayed task to record the tab's grouping state changes 10 seconds
+  // after creation. The histogram will include the tab's initial grouping state
+  // and and the ending grouping state.
+  void ScheduleRecordTabGroupingTransition();
+
+  void RecordTabGroupingTransition(
+      std::optional<tab_groups::TabGroupId> last_active_group_id);
+
+  raw_ptr<TabInterface> tab_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  base::WeakPtrFactory<TabCreationMetricsController> weak_factory_{this};
+};
+}  // namespace tabs
+
+#endif  // CHROME_BROWSER_UI_TABS_TAB_CREATION_METRICS_CONTROLLER_H_
diff --git a/chrome/browser/ui/tabs/tab_creation_metrics_controller_browsertest.cc b/chrome/browser/ui/tabs/tab_creation_metrics_controller_browsertest.cc
new file mode 100644
index 0000000..9c54b6a
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_creation_metrics_controller_browsertest.cc
@@ -0,0 +1,167 @@
+// 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 "chrome/browser/ui/tabs/tab_creation_metrics_controller.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/tabs/tab_group_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/tab_groups/tab_group_id.h"
+#include "components/tab_groups/tab_group_visual_data.h"
+#include "components/tabs/public/tab_group.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace tabs {
+
+constexpr char kHistogramName[] = "Tab.GroupingTransition";
+
+class TabCreationMetricsTest : public InProcessBrowserTest {
+ public:
+  TabCreationMetricsTest()
+      : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()) {}
+
+  void SetUpOnMainThread() override {
+    TabCreationMetricsController::SetTaskRunnerForTesting(task_runner_);
+  }
+
+  void TearDownOnMainThread() override {
+    TabCreationMetricsController::SetTaskRunnerForTesting(nullptr);
+  }
+
+ protected:
+  TabStripModel* tab_strip_model() { return browser()->tab_strip_model(); }
+  int TabCount() { return browser()->tab_strip_model()->count(); }
+
+  void AppendTab() {
+    chrome::AddTabAt(browser(), GURL(), -1, /*foreground=*/true);
+  }
+
+  void AppendTabToEndOfGroup(tab_groups::TabGroupId group_id) {
+    const auto tabs =
+        tab_strip_model()->group_model()->GetTabGroup(group_id)->ListTabs();
+    tab_strip_model()->delegate()->AddTabAt(GURL(), /*index=*/tabs.end(),
+                                            /*foreground=*/true, group_id);
+    tab_strip_model()->ActivateTabAt(tabs.end());
+  }
+
+  tab_groups::TabGroupId AddTabToNewGroup(int tab_index) {
+    tab_groups::TabGroupId group_id =
+        tab_strip_model()->AddToNewGroup({tab_index});
+    tab_strip_model()->ActivateTabAt(tab_index);
+    return group_id;
+  }
+
+  void AddTabToExistingGroup(int tab_index, tab_groups::TabGroupId group_id) {
+    tab_strip_model()->AddToExistingGroup({tab_index}, group_id);
+    tab_strip_model()->ActivateTabAt(tab_index);
+  }
+
+  void UngroupTab(int tab_index) {
+    tab_strip_model()->RemoveFromGroup({tab_index});
+    tab_strip_model()->ActivateTabAt(tab_index);
+  }
+
+  void FastForwardPastDelay() {
+    task_runner_->FastForwardBy(TabCreationMetricsController::kDelay +
+                                base::Seconds(1));
+  }
+
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+};
+
+IN_PROC_BROWSER_TEST_F(TabCreationMetricsTest, UngroupedToUngrouped) {
+  base::HistogramTester histogram_tester;
+
+  AppendTab();
+  FastForwardPastDelay();
+
+  histogram_tester.ExpectBucketCount(
+      kHistogramName, TabGroupingTransitionType::kUngroupedToUngrouped, 1);
+  histogram_tester.ExpectTotalCount(kHistogramName, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(TabCreationMetricsTest, UngroupedToGrouped) {
+  base::HistogramTester histogram_tester;
+
+  AppendTab();
+  // Group the newly created tab.
+  AddTabToNewGroup(TabCount() - 1);
+  FastForwardPastDelay();
+
+  histogram_tester.ExpectBucketCount(
+      kHistogramName, TabGroupingTransitionType::kUngroupedToGrouped, 1);
+  histogram_tester.ExpectTotalCount(kHistogramName, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(TabCreationMetricsTest, GroupedToUngrouped) {
+  // Create a tab group with a tab.
+  AppendTab();
+  tab_groups::TabGroupId active_group_id = AddTabToNewGroup(TabCount() - 1);
+
+  FastForwardPastDelay();
+  base::HistogramTester histogram_tester;
+
+  // Create a new tab in the active group.
+  AppendTabToEndOfGroup(active_group_id);
+  // Ungroup the newly created tab from the active group.
+  UngroupTab(TabCount() - 1);
+  FastForwardPastDelay();
+
+  histogram_tester.ExpectBucketCount(
+      kHistogramName, TabGroupingTransitionType::kGroupedToUngrouped, 1);
+  histogram_tester.ExpectTotalCount(kHistogramName, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(TabCreationMetricsTest, GroupedToInPreviousGroup) {
+  // Create a tab group with a tab.
+  AppendTab();
+  tab_groups::TabGroupId group_id = AddTabToNewGroup(TabCount() - 1);
+
+  FastForwardPastDelay();
+  base::HistogramTester histogram_tester;
+
+  // Create a new tab in the active group.
+  AppendTabToEndOfGroup(group_id);
+  FastForwardPastDelay();
+
+  histogram_tester.ExpectBucketCount(
+      kHistogramName, TabGroupingTransitionType::kGroupedToInPreviousGroup, 1);
+  histogram_tester.ExpectTotalCount(kHistogramName, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(TabCreationMetricsTest, GroupedToOutsidePreviousGroup) {
+  // Create group A.
+  AppendTab();
+  tab_groups::TabGroupId group_id_a = AddTabToNewGroup(TabCount() - 1);
+
+  // Create group B.
+  AppendTab();
+  tab_groups::TabGroupId group_id_b = AddTabToNewGroup(TabCount() - 1);
+
+  FastForwardPastDelay();
+  base::HistogramTester histogram_tester;
+
+  // Add tab to group A then move to group B.
+  AppendTabToEndOfGroup(group_id_a);
+  AddTabToExistingGroup(1, group_id_b);
+  FastForwardPastDelay();
+
+  histogram_tester.ExpectBucketCount(
+      kHistogramName, TabGroupingTransitionType::kGroupedToOutsidePreviousGroup,
+      1);
+  histogram_tester.ExpectTotalCount(kHistogramName, 1);
+}
+
+}  // namespace tabs
diff --git a/chrome/browser/ui/tabs/tab_dialog_manager.cc b/chrome/browser/ui/tabs/tab_dialog_manager.cc
index c94c9ed..dac21e3 100644
--- a/chrome/browser/ui/tabs/tab_dialog_manager.cc
+++ b/chrome/browser/ui/tabs/tab_dialog_manager.cc
@@ -308,7 +308,7 @@
       std::make_unique<BrowserWindowWidgetObserver>(this, tab_interface_,
                                                     widget_.get());
   widget_->Show();
-  widget_->SetVisible(GetDialogWidgetVisibility());
+  UpdateDialogVisibility();
 }
 
 std::unique_ptr<views::Widget> TabDialogManager::CreateAndShowDialog(
@@ -338,7 +338,7 @@
     return false;
   }
 
-  if (GetDialogWidgetVisibility()) {
+  if (UpdateDialogVisibility()) {
     widget_->Activate();
     return true;
   }
@@ -417,6 +417,16 @@
   }
 }
 
+bool TabDialogManager::UpdateDialogVisibility(
+    std::optional<bool> requested_visibility) {
+  if (widget_) {
+    widget_->SetVisible(GetDialogWidgetVisibility() &&
+                        requested_visibility.value_or(true));
+    return widget_->IsVisible();
+  }
+  return false;
+}
+
 void TabDialogManager::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   if (!widget_) {
@@ -460,7 +470,7 @@
     if (parent_widget != widget_->parent()) {
       widget_->Reparent(parent_widget);
     }
-    widget_->SetVisible(GetDialogWidgetVisibility());
+    UpdateDialogVisibility();
     UpdateModalDialogBounds();
   }
 }
diff --git a/chrome/browser/ui/tabs/tab_features.cc b/chrome/browser/ui/tabs/tab_features.cc
index f74c9d6..07341f6 100644
--- a/chrome/browser/ui/tabs/tab_features.cc
+++ b/chrome/browser/ui/tabs/tab_features.cc
@@ -49,6 +49,7 @@
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_web_contents_listener.h"
+#include "chrome/browser/ui/tabs/tab_creation_metrics_controller.h"
 #include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
@@ -258,6 +259,11 @@
           std::make_unique<glic::GlicTabIndicatorHelper>(&tab);
     }
 #endif  // BUILDFLAG(ENABLE_GLIC)
+    if (base::FeatureList::IsEnabled(features::kGlicActorUi)) {
+      actor_ui_tab_controller_ =
+          std::make_unique<actor::ui::ActorUiTabController>(
+              tab, actor::ActorKeyedService::Get(profile));
+    }
   }  // IsInNormalWindow() end.
 
   // This block instantiates the page action controllers that depends on the
@@ -338,16 +344,13 @@
 
   tab_alert_controller_ = std::make_unique<TabAlertController>(tab);
 
+  tab_creation_metrics_controller_ =
+      std::make_unique<TabCreationMetricsController>(&tab);
+
   tab_ui_helper_ = std::make_unique<TabUIHelper>(tab);
 
   task_manager::WebContentsTags::CreateForTabContents(tab.GetContents());
 
-  if (base::FeatureList::IsEnabled(features::kGlicActorUi)) {
-    actor_ui_tab_controller_ =
-        std::make_unique<actor::ui::ActorUiTabController>(
-            tab, actor::ActorKeyedService::Get(profile));
-  }
-
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
     BUILDFLAG(IS_CHROMEOS)
   inactive_window_mouse_event_controller_ =
diff --git a/chrome/browser/ui/tabs/tab_model.cc b/chrome/browser/ui/tabs/tab_model.cc
index 9d6d34b..6dc52edf 100644
--- a/chrome/browser/ui/tabs/tab_model.cc
+++ b/chrome/browser/ui/tabs/tab_model.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "components/constrained_window/constrained_window_views.h"
+#include "components/sessions/content/session_tab_helper.h"
 #include "components/tabs/public/split_tab_collection.h"
 #include "components/tabs/public/split_tab_id.h"
 #include "components/tabs/public/tab_collection.h"
@@ -38,8 +39,6 @@
 
 namespace tabs {
 
-DEFINE_HANDLE_FACTORY(TabInterface);
-
 namespace {
 
 bool g_disable_tab_feature_initialization = false;
@@ -81,6 +80,9 @@
   // one place, which is here.
   TabHelpers::AttachTabHelpers(contents_);
   tab_features_ = std::make_unique<TabFeatures>();
+  const SessionID session_id = sessions::SessionTabHelper::IdForTab(contents_);
+  CHECK(session_id.is_valid());
+  SetSessionId(session_id.id());
 
   // Once tabs are pulled into a standalone module, TabFeatures and its
   // initialization will need to be delegated back to the main module.
@@ -420,6 +422,11 @@
       std::move(contents_owned_);
   contents_owned_ = std::move(contents);
   contents_ = contents_owned_.get();
+
+  const SessionID session_id = sessions::SessionTabHelper::IdForTab(contents_);
+  CHECK(session_id.is_valid());
+  SetSessionId(session_id.id());
+
   TabLookupFromWebContents::CreateForWebContents(contents_, this);
   return old_contents;
 }
diff --git a/chrome/browser/ui/tabs/tab_model_unittest.cc b/chrome/browser/ui/tabs/tab_model_unittest.cc
index 9d983ec..7305c9f 100644
--- a/chrome/browser/ui/tabs/tab_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_model_unittest.cc
@@ -7,10 +7,14 @@
 #include <memory>
 
 #include "base/test/mock_callback.h"
+#include "chrome/browser/sessions/session_tab_helper_factory.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/sessions/content/session_tab_helper.h"
+#include "components/sessions/core/session_id.h"
+#include "components/tabs/public/tab_handle_factory.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
@@ -97,4 +101,57 @@
   EXPECT_FALSE(tab1->IsSelected());
 }
 
+TEST_F(TabModelTest, HandleAndSessionIdAreMapped) {
+  TestTabStripModelDelegate delegate;
+  TabStripModel tab_strip(&delegate, profile());
+  AppendTab(tab_strip);
+  tabs::TabModel* tab_model =
+      static_cast<tabs::TabModel*>(tab_strip.GetTabAtIndex(0));
+
+  // The handle should be valid.
+  EXPECT_NE(tab_model->GetHandle().raw_value(), tabs::TabHandle::NullValue);
+
+  // The factory should be able to map the handle back to the session ID.
+  auto* factory = &tabs::SessionMappedTabHandleFactory::GetInstance();
+  sessions::SessionTabHelper* session_tab_helper =
+      sessions::SessionTabHelper::FromWebContents(tab_model->GetContents());
+  EXPECT_EQ(session_tab_helper->session_id().id(),
+            factory->GetSessionIdForHandle(tab_model->GetHandle().raw_value()));
+}
+
+TEST_F(TabModelTest, DiscardContentsUpdatesSessionIdMapping) {
+  TestTabStripModelDelegate delegate;
+  TabStripModel tab_strip(&delegate, profile());
+  AppendTab(tab_strip);
+  tabs::TabModel* tab_model =
+      static_cast<tabs::TabModel*>(tab_strip.GetTabAtIndex(0));
+  auto* factory = &tabs::SessionMappedTabHandleFactory::GetInstance();
+
+  const int32_t original_session_id =
+      sessions::SessionTabHelper::FromWebContents(tab_model->GetContents())
+          ->session_id()
+          .id();
+  EXPECT_EQ(original_session_id,
+            factory->GetSessionIdForHandle(tab_model->GetHandle().raw_value()));
+
+  // Discard the contents and replace it with a new WebContents.
+  std::unique_ptr<content::WebContents> new_contents =
+      content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+  CreateSessionServiceTabHelper(new_contents.get());
+
+  const int32_t new_session_id =
+      sessions::SessionTabHelper::FromWebContents(new_contents.get())
+          ->session_id()
+          .id();
+  ASSERT_NE(original_session_id, new_session_id);
+  tab_model->DiscardContents(std::move(new_contents));
+
+  EXPECT_EQ(new_session_id,
+            factory->GetSessionIdForHandle(tab_model->GetHandle().raw_value()));
+  EXPECT_EQ(tab_model->GetHandle().raw_value(),
+            factory->GetHandleForSessionId(new_session_id));
+  EXPECT_EQ(TabHandle::Null().raw_value(),
+            factory->GetHandleForSessionId(original_session_id));
+}
+
 }  // namespace tabs
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 883018ed..7aea081 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1290,6 +1290,11 @@
   return ContainsIndex(index) ? GetTabAtIndex(index)->GetGroup() : std::nullopt;
 }
 
+std::optional<tab_groups::TabGroupId> TabStripModel::GetActiveTabGroupId()
+    const {
+  return GetTabGroupForTab(active_index());
+}
+
 std::optional<tab_groups::TabGroupId> TabStripModel::GetSurroundingTabGroup(
     int index) const {
   if (!ContainsIndex(index - 1) || !ContainsIndex(index)) {
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 3decff5a..2f09a4f 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -525,6 +525,10 @@
   // index is invalid or not grouped.
   std::optional<tab_groups::TabGroupId> GetTabGroupForTab(int index) const;
 
+  // Returns the TabGroupId of the active tab if it belongs to a group, or
+  // nullopt if ungrouped.
+  std::optional<tab_groups::TabGroupId> GetActiveTabGroupId() const;
+
   // If a tab inserted at |index| would be within a tab group, return that
   // group's ID. Otherwise, return nullopt. If |index| points to the first tab
   // in a group, it will return nullopt since a new tab would be either between
diff --git a/chrome/browser/ui/test/browser_ui_test_base.cc b/chrome/browser/ui/test/browser_ui_test_base.cc
index 97bed8ef..7cde70e6 100644
--- a/chrome/browser/ui/test/browser_ui_test_base.cc
+++ b/chrome/browser/ui/test/browser_ui_test_base.cc
@@ -2,14 +2,10 @@
 // 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 "chrome/browser/ui/test/browser_ui_test_base.h"
 
 #include "base/command_line.h"
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/logging.h"
 #include "base/process/launch.h"
@@ -38,7 +34,7 @@
     const testing::TestSuite* test_suite = unit_test->GetTestSuite(i);
     for (int j = 0; j < test_suite->total_test_count(); ++j) {
       const char* name = test_suite->GetTestInfo(j)->name();
-      if (strstr(name, kUiPattern)) {
+      if (UNSAFE_TODO(strstr(name, kUiPattern))) {
         ui_cases.insert(base::StrCat({test_suite->name(), ".", name}));
       }
     }
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
index 8c84bb1..e6e2760 100644
--- a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model_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 "chrome/browser/ui/toolbar/back_forward_menu_model.h"
 
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -591,13 +587,13 @@
   SkBitmap valid_icon_bitmap = *valid_icon.GetImage().ToSkBitmap();
 
   // Verify we did not get the default favicon.
-  EXPECT_NE(
+  UNSAFE_TODO(EXPECT_NE(
       0, memcmp(default_icon_bitmap.getPixels(), valid_icon_bitmap.getPixels(),
-                default_icon_bitmap.computeByteSize()));
+                default_icon_bitmap.computeByteSize())));
   // Verify we did get the expected favicon.
-  EXPECT_EQ(0,
-            memcmp(new_icon_bitmap.getPixels(), valid_icon_bitmap.getPixels(),
-                   new_icon_bitmap.computeByteSize()));
+  UNSAFE_TODO(EXPECT_EQ(
+      0, memcmp(new_icon_bitmap.getPixels(), valid_icon_bitmap.getPixels(),
+                new_icon_bitmap.computeByteSize())));
 
   // Make sure the browser deconstructor doesn't have problems.
   browser->tab_strip_model()->CloseAllTabs();
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 6616596..6678e736 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -589,4 +589,8 @@
   return is_tab_search_moving;
 }
 
+BASE_FEATURE(kNonMilestoneUpdateToast,
+             "NonMilestoneUpdateToast",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 }  // namespace features
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index dac6570..a3ff2fba 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -360,6 +360,9 @@
 
 bool HasTabSearchToolbarButton();
 
+// Controls whether to show a toast for Chrome non milestone update.
+BASE_DECLARE_FEATURE(kNonMilestoneUpdateToast);
+
 }  // namespace features
 
 #endif  // CHROME_BROWSER_UI_UI_FEATURES_H_
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
index 3f0f506..c5c3c0c 100644
--- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
+++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
 #include "build/build_config.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -432,6 +433,10 @@
   }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<LiveCaptionBubbleSettings> caption_bubble_settings_;
   std::unique_ptr<CaptionBubbleControllerViews> controller_;
diff --git a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
index d1524b2..5167e05 100644
--- a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
+++ b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.h"
 
+#include "base/compiler_specific.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/favicon/favicon_utils.h"
@@ -62,8 +58,8 @@
   std::optional<gfx::ImageSkia> image;
 
   // Only scale and update if the frame appears to be new.
-  const uint32_t hash = base::FastHash(base::span(
-      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize()));
+  const uint32_t hash = base::FastHash(UNSAFE_TODO(base::span(
+      static_cast<uint8_t*>(bitmap.getPixels()), bitmap.computeByteSize())));
   if (!last_hash.has_value() || hash != last_hash.value()) {
     image = ScaleBitmap(bitmap, thumbnail_size);
   }
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
index 8da3783..44d694c 100644
--- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/enterprise/data_protection/data_protection_navigation_controller.h"
 #include "chrome/browser/enterprise/watermark/watermark_view.h"
 #include "chrome/browser/policy/dm_token_utils.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/chrome_enterprise_url_lookup_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -86,7 +87,11 @@
 
 class BrowserViewTest : public InProcessBrowserTest {
  public:
-  BrowserViewTest() : devtools_(nullptr) {}
+  BrowserViewTest() : devtools_(nullptr) {
+    // TODO(crbug.com/415071842): Re-enable once DevTools is migrated to
+    // ContentsWebView.
+    scoped_feature_list_.InitWithFeatures({}, {features::kSideBySide});
+  }
 
   BrowserViewTest(const BrowserViewTest&) = delete;
   BrowserViewTest& operator=(const BrowserViewTest&) = delete;
@@ -129,6 +134,8 @@
   }
 
   raw_ptr<DevToolsWindow> devtools_;
+
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 namespace {
@@ -858,6 +865,10 @@
   }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::CallbackListSubscription create_services_subscription_;
 };
 
diff --git a/chrome/browser/ui/views/frame/contents_container_view.cc b/chrome/browser/ui/views/frame/contents_container_view.cc
index 137c909..ea9ba0a5 100644
--- a/chrome/browser/ui/views/frame/contents_container_view.cc
+++ b/chrome/browser/ui/views/frame/contents_container_view.cc
@@ -34,7 +34,12 @@
 #endif
 
 namespace {
-constexpr gfx::RoundedCornersF kContentCornerRadius{6};
+constexpr float kContentCornerRadius = 6;
+constexpr gfx::RoundedCornersF kContentRoundedCorners{kContentCornerRadius};
+constexpr gfx::RoundedCornersF kContentUpperRoundedCorners =
+    gfx::RoundedCornersF{kContentCornerRadius, kContentCornerRadius, 0, 0};
+constexpr gfx::RoundedCornersF kContentLowerRoundedCorners =
+    gfx::RoundedCornersF{0, 0, kContentCornerRadius, kContentCornerRadius};
 constexpr int kContentOutlineCornerRadius = 8;
 constexpr int kContentOutlineThickness = 1;
 constexpr int kSplitViewContentPadding = 4;
@@ -80,7 +85,7 @@
   if (base::FeatureList::IsEnabled(features::kSideBySide)) {
     inactive_split_scrim_view_ =
         AddChildView(std::make_unique<ScrimView>(kColorSplitViewScrim));
-    inactive_split_scrim_view_->SetRoundedCorners(kContentCornerRadius);
+    inactive_split_scrim_view_->SetRoundedCorners(kContentRoundedCorners);
     mini_toolbar_ = AddChildView(std::make_unique<MultiContentsViewMiniToolbar>(
         browser_view, contents_view_));
   }
@@ -89,6 +94,7 @@
 void ContentsContainerView::UpdateBorderAndOverlay(bool is_in_split,
                                                    bool is_active,
                                                    bool show_scrim) {
+  is_in_split_ = is_in_split;
   // The border, mini toolbar, and scrim should not be visible if not in a
   // split.
   if (!is_in_split) {
@@ -96,6 +102,9 @@
     contents_view_->holder()->SetCornerRadii(gfx::RoundedCornersF{0});
     contents_view_->SetBackgroundRadii(gfx::RoundedCornersF{0});
     contents_scrim_view_->SetRoundedCorners(gfx::RoundedCornersF{0});
+    if (new_tab_footer_view_) {
+      new_tab_footer_view_->holder()->SetCornerRadii(gfx::RoundedCornersF{0});
+    }
     mini_toolbar_->SetVisible(false);
     inactive_split_scrim_view_->SetVisible(false);
     return;
@@ -113,13 +122,13 @@
                                      kContentOutlineCornerRadius, color),
       gfx::Insets(kSplitViewContentPadding)));
 
-  if (contents_view_->GetBackgroundRadii() != kContentCornerRadius) {
-    contents_view_->holder()->SetCornerRadii(kContentCornerRadius);
-    contents_view_->SetBackgroundRadii(kContentCornerRadius);
-  }
+  UpdateContentsViewRoundedCorners();
   if (contents_scrim_view_->layer()->rounded_corner_radii() !=
-      kContentCornerRadius) {
-    contents_scrim_view_->SetRoundedCorners(kContentCornerRadius);
+      kContentRoundedCorners) {
+    contents_scrim_view_->SetRoundedCorners(kContentRoundedCorners);
+  }
+  if (new_tab_footer_view_) {
+    new_tab_footer_view_->holder()->SetCornerRadii(kContentLowerRoundedCorners);
   }
   // Mini toolbar should only be visible for the inactive contents
   // container view or both depending on configuration.
@@ -129,6 +138,22 @@
   inactive_split_scrim_view_->SetVisible(!is_active && show_scrim);
 }
 
+void ContentsContainerView::UpdateContentsViewRoundedCorners() {
+  auto radii = new_tab_footer_view_ && new_tab_footer_view_->GetVisible()
+                   ? kContentUpperRoundedCorners
+                   : kContentRoundedCorners;
+  if (contents_view_->GetBackgroundRadii() != radii) {
+    contents_view_->holder()->SetCornerRadii(radii);
+    contents_view_->SetBackgroundRadii(radii);
+  }
+}
+
+void ContentsContainerView::ChildVisibilityChanged(View* child) {
+  if (child == new_tab_footer_view_ && is_in_split_) {
+    UpdateContentsViewRoundedCorners();
+  }
+}
+
 views::ProposedLayout ContentsContainerView::CalculateProposedLayout(
     const views::SizeBounds& size_bounds) const {
   views::ProposedLayout layouts;
diff --git a/chrome/browser/ui/views/frame/contents_container_view.h b/chrome/browser/ui/views/frame/contents_container_view.h
index 471dd46..8d4677eb 100644
--- a/chrome/browser/ui/views/frame/contents_container_view.h
+++ b/chrome/browser/ui/views/frame/contents_container_view.h
@@ -46,10 +46,17 @@
                               bool show_scrim);
 
  private:
+  void UpdateContentsViewRoundedCorners();
+
+  // View:
+  void ChildVisibilityChanged(View* child) override;
+
   // LayoutDelegate:
   views::ProposedLayout CalculateProposedLayout(
       const views::SizeBounds& size_bounds) const override;
 
+  bool is_in_split_ = false;
+
   raw_ptr<ContentsWebView> contents_view_;
   // The scrim view that covers the content area when a tab-modal dialog is
   // open.
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller.cc b/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller.cc
index 0afe3d5f..107fe94 100644
--- a/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller.cc
+++ b/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller.cc
@@ -81,6 +81,13 @@
     const content::DropData& data,
     const gfx::PointF& point,
     bool is_in_split_view) {
+  // "Drag update" events can still be delivered even if the point is out of the
+  // contents area, particularly while the drop target is animating in and
+  // shifting them.
+  if ((point.x() < 0) || (point.x() > drop_target_parent_view_->width())) {
+    ResetDropTargetTimer();
+    return;
+  }
   if (!data.url.is_valid() || is_in_split_view) {
     ResetDropTargetTimer();
     return;
diff --git a/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_unittest.cc b/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_unittest.cc
index 22d2e141..edc2d26 100644
--- a/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_unittest.cc
+++ b/chrome/browser/ui/views/frame/multi_contents_view_drop_target_controller_unittest.cc
@@ -211,6 +211,34 @@
   EXPECT_FALSE(drop_target_view().GetVisible());
 }
 
+// Tests that the drop target is not shown when a drag is started from a
+// tab that is already in a split view.
+TEST_F(MultiContentsViewDropTargetControllerTest,
+       OnWebContentsDragUpdate_HideDropTargetWhenInSplitView) {
+  controller().OnWebContentsDragUpdate(ValidUrlDropData(),
+                                       kDragPointForStartDropTargetShow, true);
+
+  FastForward();
+  EXPECT_FALSE(drop_target_view().GetVisible());
+}
+
+// Tests that the drop target is not shown when a drag is outside of the
+// contents view.
+TEST_F(MultiContentsViewDropTargetControllerTest,
+       OnWebContentsDragUpdate_HideDropTargetWhenDragIsOutOfBounds) {
+  controller().OnWebContentsDragUpdate(ValidUrlDropData(), gfx::PointF(-1, 250),
+                                       false);
+
+  FastForward();
+  EXPECT_FALSE(drop_target_view().GetVisible());
+
+  controller().OnWebContentsDragUpdate(ValidUrlDropData(), gfx::PointF(1000, 250),
+                                       false);
+
+  FastForward();
+  EXPECT_FALSE(drop_target_view().GetVisible());
+}
+
 // Tests that the drop target timer is cancelled when a drag is not in the
 // "drop area".
 TEST_F(MultiContentsViewDropTargetControllerTest,
diff --git a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc
index db11fec..23fe8fe 100644
--- a/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/picture_in_picture_browser_frame_view_interactive_uitest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/picture_in_picture/picture_in_picture_occlusion_tracker.h"
 #include "chrome/browser/picture_in_picture/picture_in_picture_widget_fade_animator.h"
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -358,6 +359,10 @@
   PictureInPictureBrowserFrameView* pip_frame_view() { return pip_frame_view_; }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList scoped_feature_list_;
   raw_ptr<PictureInPictureBrowserFrameView, AcrossTasksDanglingUntriaged>
       pip_frame_view_ = nullptr;
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
index 7da9db3..6ff349f 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -87,6 +87,16 @@
          !browser->GetAppBrowserController()->ShouldHideNewTabButton();
 }
 
+// Updates the border of `view` if the insets need to be updated.
+void UpdateBorderInsetsIfNeeded(views::View* view,
+                                const gfx::Insets& new_border_insets) {
+  CHECK(view);
+  if (!view->GetBorder() ||
+      view->GetBorder()->GetInsets() != new_border_insets) {
+    view->SetBorder(views::CreateEmptyBorder(new_border_insets));
+  }
+}
+
 }  // namespace
 
 TabStripRegionView::TabStripRegionView(std::unique_ptr<TabStrip> tab_strip)
@@ -528,24 +538,23 @@
   if (tab_strip_action_container_) {
     tab_strip_action_container_->UpdateButtonBorders(border_insets);
   }
+  if (new_tab_button_) {
+    UpdateBorderInsetsIfNeeded(new_tab_button_, border_insets);
+  }
+  if (tab_search_container_) {
+    UpdateBorderInsetsIfNeeded(tab_search_container_->tab_search_button(),
+                               border_insets);
 
-    if (new_tab_button_) {
-      new_tab_button_->SetBorder(views::CreateEmptyBorder(border_insets));
+    if (tab_search_container_->auto_tab_group_button()) {
+      UpdateBorderInsetsIfNeeded(tab_search_container_->auto_tab_group_button(),
+                                 border_insets);
     }
-    if (tab_search_container_) {
-      tab_search_container_->tab_search_button()->SetBorder(
-          views::CreateEmptyBorder(border_insets));
 
-      if (tab_search_container_->auto_tab_group_button()) {
-        tab_search_container_->auto_tab_group_button()->SetBorder(
-            views::CreateEmptyBorder(border_insets));
-      }
-
-      if (tab_search_container_->tab_declutter_button()) {
-        tab_search_container_->tab_declutter_button()->SetBorder(
-            views::CreateEmptyBorder(border_insets));
-      }
+    if (tab_search_container_->tab_declutter_button()) {
+      UpdateBorderInsetsIfNeeded(tab_search_container_->tab_declutter_button(),
+                                 border_insets);
     }
+  }
 }
 
 void TabStripRegionView::UpdateTabStripMargin() {
diff --git a/chrome/browser/ui/views/passwords/password_change/password_change_toast.cc b/chrome/browser/ui/views/passwords/password_change/password_change_toast.cc
index d585415..73397d3d 100644
--- a/chrome/browser/ui/views/passwords/password_change/password_change_toast.cc
+++ b/chrome/browser/ui/views/passwords/password_change/password_change_toast.cc
@@ -128,10 +128,6 @@
   action_button_->SetEnabledTextColors(ui::kColorToastButton);
   action_button_->SetBgColorIdOverride(ui::kColorToastBackgroundProminent);
   action_button_->SetStrokeColorIdOverride(ui::kColorToastButton);
-  action_button_->SetPreferredSize(
-      gfx::Size(action_button_->GetPreferredSize().width(),
-                layout_provider->GetDistanceMetric(
-                    DISTANCE_TOAST_BUBBLE_HEIGHT_ACTION_BUTTON)));
   action_button_->SetStyle(ui::ButtonStyle::kProminent);
   action_button_->SetProperty(views::kElementIdentifierKey,
                               kPasswordChangeActionButton);
@@ -161,13 +157,39 @@
   close_button_->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_TOAST_CLOSE_TOOLTIP));
 
-  UpdateConfiguration(std::move(toast_configuration));
+  UpdateLayout(std::move(toast_configuration));
 }
 
 PasswordChangeToast::~PasswordChangeToast() = default;
 
 void PasswordChangeToast::UpdateLayout(ToastOptions configuration) {
-  UpdateConfiguration(std::move(configuration));
+  action_button_closure_ = std::move(configuration.action_button_closure);
+  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
+  icon_ = configuration.icon;
+  icon_view_->SetVisible(icon_.has_value());
+  if (icon_.has_value() && GetColorProvider()) {
+    icon_view_->SetImage(ui::ImageModel::FromVectorIcon(
+        *icon_.value(), GetColorProvider()->GetColor(ui::kColorToastForeground),
+        layout_provider->GetDistanceMetric(DISTANCE_TOAST_BUBBLE_ICON_SIZE)));
+  }
+  throbber_->SetVisible(!icon_.has_value());
+
+  label_->SetText(configuration.text);
+
+  if (configuration.action_button_text.has_value()) {
+    action_button_->SetText(configuration.action_button_text.value());
+
+    // Only set kAlert a11y role when text is not empty, otherwise it triggers
+    // a DCHECK in views::RunAccessibilityPaintChecks().
+    action_button_->GetViewAccessibility().SetRole(ax::mojom::Role::kAlert);
+    action_button_->SetVisible(true);
+  } else {
+    action_button_->GetViewAccessibility().SetRole(ax::mojom::Role::kButton);
+    action_button_->SetVisible(false);
+  }
+  close_button_->SetVisible(configuration.has_close_button);
+
+  layout_manager_->SetInteriorMargin(CalculateInteriorMargin());
 }
 
 gfx::Insets PasswordChangeToast::CalculateInteriorMargin() {
@@ -193,47 +215,6 @@
       layout_provider->GetDistanceMetric(right_margin_token));
 }
 
-void PasswordChangeToast::UpdateConfiguration(ToastOptions configuration) {
-  action_button_closure_ = std::move(configuration.action_button_closure);
-  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
-  icon_ = configuration.icon;
-  icon_view_->SetVisible(icon_.has_value());
-  if (icon_.has_value() && GetColorProvider()) {
-    icon_view_->SetImage(ui::ImageModel::FromVectorIcon(
-        *icon_.value(), GetColorProvider()->GetColor(ui::kColorToastForeground),
-        layout_provider->GetDistanceMetric(DISTANCE_TOAST_BUBBLE_ICON_SIZE)));
-  }
-  throbber_->SetVisible(!icon_.has_value());
-
-  label_->SetText(configuration.text);
-
-  if (configuration.action_button_text.has_value()) {
-    action_button_->SetText(configuration.action_button_text.value());
-    auto tmp_button = std::make_unique<views::MdTextButton>(
-        views::Button::PressedCallback(),
-        configuration.action_button_text.value_or(std::u16string()));
-    // Even though the text might change
-    // action_button_->GetPreferredSize().width() is not updated properly, this
-    // is why a temporary button is created to set preferred size manually.
-    action_button_->SetPreferredSize(
-        gfx::Size(tmp_button->GetPreferredSize().width(),
-                  layout_provider->GetDistanceMetric(
-                      DISTANCE_TOAST_BUBBLE_HEIGHT_ACTION_BUTTON)));
-  }
-  if (configuration.action_button_text.has_value()) {
-    // Only set kAlert a11y role when text is not empty, otherwise it triggers
-    // a DCHECK in views::RunAccessibilityPaintChecks().
-    action_button_->GetViewAccessibility().SetRole(ax::mojom::Role::kAlert);
-    action_button_->SetVisible(true);
-  } else {
-    action_button_->GetViewAccessibility().SetRole(ax::mojom::Role::kButton);
-    action_button_->SetVisible(false);
-  }
-  close_button_->SetVisible(configuration.has_close_button);
-
-  layout_manager_->SetInteriorMargin(CalculateInteriorMargin());
-}
-
 void PasswordChangeToast::OnThemeChanged() {
   views::View::OnThemeChanged();
 
diff --git a/chrome/browser/ui/views/passwords/password_change/password_change_toast.h b/chrome/browser/ui/views/passwords/password_change/password_change_toast.h
index e65b3d25..86d6515 100644
--- a/chrome/browser/ui/views/passwords/password_change/password_change_toast.h
+++ b/chrome/browser/ui/views/passwords/password_change/password_change_toast.h
@@ -19,7 +19,7 @@
 }  // namespace views
 
 // Toast view displaying the progress of password change. Displayed content can
-// be updated using UpdateConfiguration() without closing the toast.
+// be updated using `UpdateLayout()` without closing the toast.
 class PasswordChangeToast : public views::View {
   METADATA_HEADER(PasswordChangeToast, views::View)
  public:
@@ -68,8 +68,6 @@
   views::ImageButton* close_button() { return close_button_; }
 
  private:
-  void UpdateConfiguration(ToastOptions configuration);
-
   // Calculates interior margins based on currently visible child views.
   gfx::Insets CalculateInteriorMargin();
 
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 7232009..8c7c66f 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -103,6 +103,10 @@
 #include "ui/aura/env.h"
 #endif
 
+#if BUILDFLAG(ENABLE_GLIC)
+#include "chrome/browser/glic/browser_ui/glic_tab_underline_view.h"
+#endif
+
 using base::UserMetricsAction;
 namespace {
 
@@ -250,6 +254,21 @@
   alert_indicator_button_ =
       AddChildView(std::make_unique<AlertIndicatorButton>(this));
 
+#if BUILDFLAG(ENABLE_GLIC)
+  if (base::FeatureList::IsEnabled(features::kGlicMultitabUnderlines)) {
+    glic_tab_underline_view_ = AddChildView(
+        views::Builder<glic::GlicTabUnderlineView>(
+            std::make_unique<glic::GlicTabUnderlineView>(
+                controller->GetBrowser(), this))
+            // Needed so that expectations of visibility that
+            // inform underline updates are correct on first show.
+            .SetVisible(false)
+            // `glic_tab_underline_view_` should never receive input events.
+            .SetCanProcessEventsWithinSubtree(false)
+            .Build());
+  }
+#endif
+
   // Unretained is safe here because this class outlives its close button, and
   // the controller outlives this Tab.
   close_button_ = AddChildView(std::make_unique<TabCloseButton>(
@@ -331,6 +350,13 @@
 
   const int start = contents_rect.x();
 
+#if BUILDFLAG(ENABLE_GLIC)
+  if (glic_tab_underline_view_) {
+    gfx::Rect glic_bounds = contents_rect + gfx::Vector2d(0, 9);
+    glic_tab_underline_view_->SetBoundsRect(glic_bounds);
+  }
+#endif
+
   // The bounds for the favicon will include extra width for the attention
   // indicator, but visually it will be smaller at kFaviconSize wide.
   gfx::Rect favicon_bounds(start, contents_rect.y(), 0, 0);
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 13e379a..4135283 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -11,10 +11,12 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
+#include "chrome/browser/glic/browser_ui/glic_tab_underline_view.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_view.h"
 #include "chrome/browser/ui/views/tabs/tab_style_views.h"
+#include "chrome/common/buildflags.h"
 #include "components/performance_manager/public/freezing/freezing.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "ui/base/metadata/metadata_header_macros.h"
@@ -47,6 +49,12 @@
 enum class TabAlert;
 }
 
+#if BUILDFLAG(ENABLE_GLIC)
+namespace glic {
+class GlicTabUnderlineView;
+}  // namespace glic
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 //
 //  A View that renders a Tab in a TabStrip.
@@ -263,6 +271,10 @@
   // True if the tab is being animated closed.
   bool closing_ = false;
 
+#if BUILDFLAG(ENABLE_GLIC)
+  raw_ptr<glic::GlicTabUnderlineView> glic_tab_underline_view_ = nullptr;
+#endif
+
   raw_ptr<TabIcon> icon_ = nullptr;
   raw_ptr<AlertIndicatorButton> alert_indicator_button_ = nullptr;
   raw_ptr<TabCloseButton> close_button_ = nullptr;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 716069856..e1a2c72 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -49,6 +49,7 @@
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/features.h"
+#include "chrome/browser/ui/tabs/new_tab_grouping_user_data.h"
 #include "chrome/browser/ui/tabs/tab_group_theme.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_prefs.h"
@@ -2259,6 +2260,10 @@
   base::RecordAction(base::UserMetricsAction("NewTab_Button"));
   UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", NewTabTypes::NEW_TAB_BUTTON,
                             NewTabTypes::NEW_TAB_ENUM_COUNT);
+  GetBrowser()->profile()->SetUserData(
+      NewTabGroupingUserData::kNewTabGroupingUserDataKey,
+      std::make_unique<NewTabGroupingUserData>(
+          GetBrowser()->tab_strip_model()->GetActiveTabGroupId()));
   if (event.IsMouseEvent()) {
     // Prevent the hover card from popping back in immediately. This forces a
     // normal fade-in.
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
index 2c2e398..29a1206 100644
--- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc
+++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -13,6 +13,7 @@
 #include "base/notreached.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "chrome/browser/devtools/features.h"
 #include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
 #include "chrome/browser/privacy_sandbox/privacy_sandbox_queue_manager.h"
@@ -1696,6 +1697,12 @@
                                "Used to test \"New\" Badge logic.")));
 
   registry.RegisterFeature(user_education::NewBadgeSpecification(
+      features::kDevToolsAiAssistanceFileAgent,
+      user_education::Metadata(132, "wolfi@chromium.org, kimanh@chromium.org",
+                               "Shown in the Sources panel in the AI menu item "
+                               "when opening the context menu of a file.")));
+
+  registry.RegisterFeature(user_education::NewBadgeSpecification(
       compose::features::kEnableCompose,
       user_education::Metadata(124, "dewittj@chromium.org",
                                "Shown in Help Me Write context menu item.", {},
diff --git a/chrome/browser/ui/views/web_apps/isolated_web_apps/multi_capture_notification_details_view.cc b/chrome/browser/ui/views/web_apps/isolated_web_apps/multi_capture_notification_details_view.cc
index 5d161f6..92446bea 100644
--- a/chrome/browser/ui/views/web_apps/isolated_web_apps/multi_capture_notification_details_view.cc
+++ b/chrome/browser/ui/views/web_apps/isolated_web_apps/multi_capture_notification_details_view.cc
@@ -97,8 +97,7 @@
     auto* app_icon =
         app_row->AddChildView(std::make_unique<views::ImageView>());
     app_icon->SetImage(ui::ImageModel::FromVectorIcon(
-        // TODO(crbug.com/424102053): Replace with finalized icon.
-        vector_icons::kScreenShareIcon, ui::kColorIconSecondary, 16));
+        vector_icons::kScreenRecordIcon, ui::kColorIconSecondary, 16));
 
     app_row->AddChildView(std::make_unique<views::Label>(
         base::UTF8ToUTF16(app_name), views::style::CONTEXT_LABEL));
@@ -148,8 +147,7 @@
 
   auto* admin_icon = AddChildView(std::make_unique<views::ImageView>());
   admin_icon->SetImage(ui::ImageModel::FromVectorIcon(
-      // TODO(crbug.com/424102053): Replace with finalized icon.
-      vector_icons::kScreenShareIcon, ui::kColorIcon, 24));
+      vector_icons::kScreenRecordIcon, ui::kColorIcon, 24));
   admin_icon->SetHorizontalAlignment(views::ImageView::Alignment::kLeading);
   admin_icon->SetProperty(
       views::kMarginsKey,
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc
index 32ebfcd4..de8e533 100644
--- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc
+++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.cc
@@ -81,7 +81,7 @@
 }
 
 FedCmAccountSelectionView::~FedCmAccountSelectionView() {
-  Close(/*notify_delegate=*/false);
+  Close(/*notify_delegate=*/false, /*hide_widget=*/false);
 }
 
 void FedCmAccountSelectionView::ShowDialogWidget() {
@@ -192,7 +192,7 @@
   // and other parts of the header.
   if ((rp_mode == blink::mojom::RpMode::kPassive && idp_list_.size() > 1) ||
       (rp_mode == blink::mojom::RpMode::kActive && !has_modal_support)) {
-    Close(/*notify_delegate=*/false);
+    Close(/*notify_delegate=*/false, /*hide_widget=*/false);
   }
 
   bool create_view = !account_selection_view_;
@@ -342,7 +342,7 @@
   // title and other parts of the header.
   if ((rp_mode == blink::mojom::RpMode::kPassive && idp_list_.size() > 1) ||
       (rp_mode == blink::mojom::RpMode::kActive && !has_modal_support)) {
-    Close(/*notify_delegate=*/false);
+    Close(/*notify_delegate=*/false, /*hide_widget=*/false);
   }
 
   bool create_view = !account_selection_view_;
@@ -380,7 +380,7 @@
   // and other parts of the header.
   if ((rp_mode == blink::mojom::RpMode::kPassive && idp_list_.size() > 1) ||
       (rp_mode == blink::mojom::RpMode::kActive && !has_modal_support)) {
-    Close(/*notify_delegate=*/false);
+    Close(/*notify_delegate=*/false, /*hide_widget=*/false);
   }
 
   bool create_view = !account_selection_view_;
@@ -509,7 +509,7 @@
 
 void FedCmAccountSelectionView::PrimaryPageChanged(content::Page& page) {
   // Close the dialog when the user navigates within the same tab.
-  Close(/*notify_delegate=*/true);
+  Close(/*notify_delegate=*/true, /*hide_widget=*/false);
 }
 
 void FedCmAccountSelectionView::SetInputEventActivationProtectorForTesting(
@@ -839,7 +839,7 @@
   // tab and subscription to avoid doing unnecessary work.
   tab_ = nullptr;
   tab_subscriptions_.clear();
-  Close(/*notify_delegate=*/true);
+  Close(/*notify_delegate=*/true, /*hide_widget=*/false);
 }
 
 void FedCmAccountSelectionView::ModalUIChanged(tabs::TabInterface* tab) {
@@ -861,7 +861,7 @@
   }
   // If the tab is going to be detached from the window then we must clear all
   // window-scoped UI.
-  Close(/*notify_delegate=*/true);
+  Close(/*notify_delegate=*/true, /*hide_widget=*/false);
 }
 
 FedCmModalDialogView* FedCmAccountSelectionView::GetPopupWindowForTesting() {
@@ -876,7 +876,7 @@
     UpdateDialogVisibilityAndPosition();
     return;
   }
-  Close(/*notify_delegate=*/true);
+  Close(/*notify_delegate=*/true, /*hide_widget=*/false);
 }
 
 bool FedCmAccountSelectionView::NotifyDelegateOfAccountSelection(
@@ -929,14 +929,15 @@
   }
 }
 
-void FedCmAccountSelectionView::Close(bool notify_delegate) {
+void FedCmAccountSelectionView::Close(bool notify_delegate, bool hide_widget) {
   if (!GetDialogWidget()) {
     CHECK(!account_selection_view_);
     return;
   }
 
   // The widget is synchronously destroyed.
-  CloseWidget(notify_delegate, views::Widget::ClosedReason::kUnspecified);
+  CloseWidget(notify_delegate, views::Widget::ClosedReason::kUnspecified,
+              hide_widget);
 }
 
 views::Widget* FedCmAccountSelectionView::GetDialogWidget() {
@@ -1145,9 +1146,9 @@
   }
 }
 
-void FedCmAccountSelectionView::CloseWidget(
-    bool notify_delegate,
-    views::Widget::ClosedReason reason) {
+void FedCmAccountSelectionView::CloseWidget(bool notify_delegate,
+                                            views::Widget::ClosedReason reason,
+                                            bool hide_widget) {
   DismissReason dismiss_reason =
       reason == views::Widget::ClosedReason::kCloseButtonClicked
           ? DismissReason::kCloseButton
@@ -1176,7 +1177,7 @@
   // dialog is just informative.
   bool notify_delegate =
       state_ != State::AUTO_REAUTHN && state_ != State::VERIFYING;
-  CloseWidget(notify_delegate, reason);
+  CloseWidget(notify_delegate, reason, false);
 }
 
 void FedCmAccountSelectionView::UpdateDialogVisibilityAndPosition() {
diff --git a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h
index 769c195..8be7daa 100644
--- a/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h
+++ b/chrome/browser/ui/views/webid/fedcm_account_selection_view_desktop.h
@@ -120,8 +120,12 @@
   // this method from being called.
   void OnPopupWindowDestroyed() override;
 
-  // Programmatically closes the widget. This is never from user action.
-  void Close(bool notify_delegate);
+  // Close always destroys the widget. If `hide_widget` is true, the contents
+  // view is extracted from the widget and parked (see comment for
+  // parked_dialog_view_). This view is possibly used later if the dialog is
+  // recreated and shown with the same content. This is never called from a user
+  // action.
+  void Close(bool notify_delegate, bool hide_widget);
 
   // content::WebContentsObserver
   void PrimaryPageChanged(content::Page& page) override;
@@ -397,7 +401,9 @@
 
   // Synchronously closes dialog_widget_. This method can result in synchronous
   // destruction of `this`.
-  void CloseWidget(bool notify_delegate, views::Widget::ClosedReason reason);
+  void CloseWidget(bool notify_delegate,
+                   views::Widget::ClosedReason reason,
+                   bool hide_widget);
 
   // Called when the user closes the dialog. This is called by
   // OnCloseButtonClicked() if the user clicks the close button, and directly
diff --git a/chrome/browser/ui/web_applications/web_app_launch_utils.cc b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
index 0031728..e4b86c8 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
@@ -103,8 +103,8 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/ash/app_mode/web_app/web_kiosk_browser_controller_ash.h"
 #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/chromeos/app_mode/web_kiosk_browser_controller_base.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/web_applications/chromeos_web_app_experiments.h"
 #include "chromeos/ash/experiences/system_web_apps/types/system_web_app_delegate.h"
@@ -138,7 +138,7 @@
 
   ReparentWebContentsIntoBrowserImpl(
       source_browser, contents, target_browser,
-      /*insert_as_pinned_first_tab=*/insert_as_pinned_home_tab);
+      /*insert_as_pinned_home_tab=*/insert_as_pinned_home_tab);
   return target_browser;
 }
 
@@ -161,8 +161,8 @@
     Browser* browser,
     WebAppProvider* provider,
     const webapps::AppId& app_id) {
-  return std::make_unique<ash::WebKioskBrowserControllerAsh>(*provider, browser,
-                                                             app_id);
+  return std::make_unique<chromeos::WebKioskBrowserControllerBase>(
+      *provider, browser, app_id);
 }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
diff --git a/chrome/browser/ui/webauthn/passkey_upgrade_request_controller.cc b/chrome/browser/ui/webauthn/passkey_upgrade_request_controller.cc
index d7311691..46c8ad0 100644
--- a/chrome/browser/ui/webauthn/passkey_upgrade_request_controller.cc
+++ b/chrome/browser/ui/webauthn/passkey_upgrade_request_controller.cc
@@ -123,8 +123,7 @@
   syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(profile());
   password_manager::PasswordStoreInterface* password_store = nullptr;
-  if (password_manager::features_util::IsAccountStorageEnabled(
-          profile()->GetPrefs(), sync_service)) {
+  if (password_manager::features_util::IsAccountStorageEnabled(sync_service)) {
     password_store = AccountPasswordStoreFactory::GetForProfile(
                          profile(), ServiceAccessType::EXPLICIT_ACCESS)
                          .get();
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
index fdd8236..6e13739c 100644
--- a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
+++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
@@ -265,7 +265,6 @@
     prefs->SetInteger(
         password_manager::prefs::kCurrentMigrationVersionToGoogleMobileServices,
         0);
-    prefs->SetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt, 0.0);
   }
   FireWebUIListener("enable-reset-upm-eviction-button",
                     base::Value(!is_user_unenrolled));
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index aec03a3..f9e7c5b 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/new_tab_page/modules/v2/calendar/google_calendar_page_handler.h"
 #include "chrome/browser/new_tab_page/modules/v2/calendar/outlook_calendar_page_handler.h"
 #include "chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption_page_handler.h"
+#include "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler.h"
 #include "chrome/browser/new_tab_page/new_tab_page_util.h"
 #include "chrome/browser/page_image_service/image_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -480,8 +481,8 @@
        IDS_NTP_COMPOSE_CANCEL_BUTTON_A11Y_LABEL_INPUT},
       {"composeboxImageUploadButtonTitle",
        IDS_NTP_COMPOSE_IMAGE_UPLOAD_BUTTON_A11Y_LABEL},
-      {"composeboxFileUploadButtonTitle",
-       IDS_NTP_COMPOSE_FILE_UPLOAD_BUTTON_A11Y_LABEL},
+      {"composeboxPdfUploadButtonTitle",
+       IDS_NTP_COMPOSE_PDF_UPLOAD_BUTTON_A11Y_LABEL},
       {"composeboxPlaceholderText", IDS_NTP_COMPOSE_PLACEHOLDER_TEXT},
       {"composeboxSubmitButtonTitle", IDS_NTP_COMPOSE_SUBMIT_BUTTON_A11Y_LABEL},
       {"composeboxDeleteFileTitle", IDS_NTP_COMPOSE_DELETE_FILE_A11Y_LABEL},
@@ -774,6 +775,13 @@
 #endif
 
 void NewTabPageUI::BindInterface(
+    mojo::PendingReceiver<ntp::tab_groups::mojom::PageHandler>
+        pending_page_handler) {
+  tab_groups_handler_ = std::make_unique<TabGroupsPageHandler>(
+      std::move(pending_page_handler), web_contents());
+}
+
+void NewTabPageUI::BindInterface(
     mojo::PendingReceiver<ntp::most_relevant_tab_resumption::mojom::PageHandler>
         pending_page_handler) {
   most_relevant_tab_resumption_handler_ =
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
index a23dffb..702de00 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/new_tab_page/modules/v2/calendar/google_calendar.mojom.h"
 #include "chrome/browser/new_tab_page/modules/v2/calendar/outlook_calendar.mojom.h"
 #include "chrome/browser/new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption.mojom.h"
+#include "chrome/browser/new_tab_page/modules/v2/tab_groups/tab_groups.mojom.h"
 #include "chrome/browser/ui/webui/new_tab_page/ntp_promo/ntp_promo.mojom.h"
 #include "chrome/browser/ui/webui/new_tab_page/ntp_promo/ntp_promo_handler.h"
 #include "components/user_education/webui/help_bubble_handler.h"
@@ -87,6 +88,7 @@
 class PrefService;
 class Profile;
 class RealboxHandler;
+class TabGroupsPageHandler;
 class NewTabPageUI;
 
 class NewTabPageUIConfig : public content::DefaultWebUIConfig<NewTabPageUI> {
@@ -214,6 +216,9 @@
       mojo::PendingReceiver<foo::mojom::FooHandler> pending_receiver);
 #endif
 
+  void BindInterface(mojo::PendingReceiver<ntp::tab_groups::mojom::PageHandler>
+                         pending_page_handler);
+
   void BindInterface(mojo::PendingReceiver<
                      ntp::most_relevant_tab_resumption::mojom::PageHandler>
                          pending_page_handler);
@@ -349,6 +354,7 @@
   std::unique_ptr<MicrosoftAuthPageHandler> microsoft_auth_handler_;
   std::unique_ptr<MicrosoftFilesPageHandler> microsoft_files_handler_;
   std::unique_ptr<OutlookCalendarPageHandler> outlook_calendar_handler_;
+  std::unique_ptr<TabGroupsPageHandler> tab_groups_handler_;
   PrefChangeRegistrar pref_change_registrar_;
 
   base::WeakPtrFactory<NewTabPageUI> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc b/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc
index 450fe63..e375582d 100644
--- a/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc
+++ b/chrome/browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/containers/contains.h"
 #include "base/stl_util.h"
 #include "base/test/mock_callback.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
@@ -93,6 +94,10 @@
   }
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList feature_list_;
 };
 
diff --git a/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc b/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc
index dafe8efd..c1c6574 100644
--- a/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc
@@ -18,6 +18,7 @@
 #include "components/optimization_guide/core/model_execution/model_execution_manager.h"
 #include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
 #include "components/optimization_guide/core/model_execution/model_execution_util.h"
+#include "components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_component.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_service_controller.h"
 #include "components/optimization_guide/core/model_execution/performance_class.h"
@@ -332,12 +333,9 @@
       optimization_guide::features::GetOnDeviceModelCrashCountBeforeDisable();
 
   // Get data on feature adaptations.
-  const base::flat_map<optimization_guide::ModelBasedCapabilityKey,
-                       optimization_guide::OnDeviceModelAdaptationMetadata>&
-      feature_adaptations =
-          optimization_guide_keyed_service_->GetModelExecutionManager()
-              ->GetOnDeviceModelServiceController()
-              ->model_adaptation_metadata();
+  optimization_guide::OnDeviceModelServiceController& controller =
+      *optimization_guide_keyed_service_->GetModelExecutionManager()
+           ->GetOnDeviceModelServiceController();
   const PrefService* local_state = g_browser_process->local_state();
   for (const auto feature : optimization_guide::kAllModelBasedCapabilityKeys) {
     if (!optimization_guide::features::internal::
@@ -349,13 +347,11 @@
     feature_adaptation_info->feature_key = static_cast<int32_t>(feature);
     feature_adaptation_info->is_recently_used =
         WasOnDeviceEligibleFeatureRecentlyUsed(feature, *local_state);
-
-    auto it = feature_adaptations.find(feature);
-    if (it != feature_adaptations.end()) {
-      feature_adaptation_info->version = it->second.version();
-    } else {
-      feature_adaptation_info->version = 0;
-    }
+    feature_adaptation_info->version =
+        controller.GetFeatureMetadata(feature)
+            .transform(
+                &optimization_guide::OnDeviceModelAdaptationMetadata::version)
+            .value_or(0);
     data->feature_adaptations.push_back(std::move(feature_adaptation_info));
   }
   data->min_vram_mb = GetMinimumVramRequired();
diff --git a/chrome/browser/ui/webui/password_manager/BUILD.gn b/chrome/browser/ui/webui/password_manager/BUILD.gn
new file mode 100644
index 0000000..7553c2d
--- /dev/null
+++ b/chrome/browser/ui/webui/password_manager/BUILD.gn
@@ -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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+  sources = [ "password_manager.mojom" ]
+  webui_module_path = "/"
+}
+
+source_set("password_manager_ui_handler") {
+  sources = [
+    "password_manager_ui_handler.cc",
+    "password_manager_ui_handler.h",
+  ]
+  deps = [
+    ":mojo_bindings",
+    "//chrome/browser/extensions",
+    "//content/public/browser",
+    "//mojo/public/cpp/bindings",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "password_manager_ui_handler_unittest.cc" ]
+  deps = [
+    ":password_manager_ui_handler",
+    "//base/test:test_support",
+    "//chrome/browser/extensions",
+    "//chrome/browser/extensions:test_support",
+    "//chrome/test:test_support",
+    "//components/password_manager/core/browser",
+    "//components/password_manager/core/browser/password_store:test_support",
+    "//content/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/browser/ui/webui/password_manager/OWNERS b/chrome/browser/ui/webui/password_manager/OWNERS
index d3837c7..e8a1b865 100644
--- a/chrome/browser/ui/webui/password_manager/OWNERS
+++ b/chrome/browser/ui/webui/password_manager/OWNERS
@@ -1 +1,4 @@
 file://chrome/browser/resources/password_manager/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/password_manager/password_manager.mojom b/chrome/browser/ui/webui/password_manager/password_manager.mojom
new file mode 100644
index 0000000..a91830d7
--- /dev/null
+++ b/chrome/browser/ui/webui/password_manager/password_manager.mojom
@@ -0,0 +1,23 @@
+// 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.
+
+module password_manager.mojom;
+
+// Used by the WebUI page to bootstrap bidirectional communication.
+interface PageHandlerFactory {
+  // The WebUI page's |BrowserProxy| singleton calls this method when the
+  // page is first initialized.
+  CreatePageHandler(
+      pending_remote<Page> page, pending_receiver<PageHandler> handler);
+};
+
+// Called from TS side of chrome://password-manager (Renderer -> Browser)
+interface PageHandler {
+  // Deletes all password manager data (passwords, passkeys, etc.)
+  // Returns whether the deletion was successful.
+  DeleteAllPasswordManagerData() => (bool success);
+};
+
+// Called from C++ side of chrome://password-manager. (Browser -> Renderer)
+interface Page {};
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 3adbdc6..c2e7fa1 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -778,3 +778,19 @@
           PasswordManagerUI::kAccountStoreToggleElementId,
           PasswordManagerUI::kOverflowMenuElementId});
 }
+
+void PasswordManagerUI::BindInterface(
+    mojo::PendingReceiver<password_manager::mojom::PageHandlerFactory>
+        receiver) {
+  password_manager_page_factory_receiver_.reset();
+  password_manager_page_factory_receiver_.Bind(std::move(receiver));
+}
+
+void PasswordManagerUI::CreatePageHandler(
+    mojo::PendingRemote<password_manager::mojom::Page> page,
+    mojo::PendingReceiver<password_manager::mojom::PageHandler> receiver) {
+  DCHECK(page);
+  password_manager_ui_handler_ = std::make_unique<PasswordManagerUIHandler>(
+      std::move(receiver), std::move(page), passwords_private_delegate_,
+      web_ui()->GetWebContents());
+}
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.h b/chrome/browser/ui/webui/password_manager/password_manager_ui.h
index 34435ee..75574a61 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.h
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.h
@@ -5,11 +5,15 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_PASSWORD_MANAGER_PASSWORD_MANAGER_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_PASSWORD_MANAGER_PASSWORD_MANAGER_UI_H_
 
+#include "chrome/browser/ui/webui/password_manager/password_manager.mojom.h"
+#include "chrome/browser/ui/webui/password_manager/password_manager_ui_handler.h"
 #include "components/password_manager/content/common/web_ui_constants.h"
 #include "components/user_education/webui/help_bubble_handler.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/resource/resource_scale_factor.h"
 #include "ui/webui/mojo_web_ui_controller.h"
@@ -39,6 +43,7 @@
 };
 
 class PasswordManagerUI : public ui::MojoWebUIController,
+                          public password_manager::mojom::PageHandlerFactory,
                           public help_bubble::mojom::HelpBubbleHandlerFactory {
  public:
   explicit PasswordManagerUI(content::WebUI* web_ui);
@@ -58,6 +63,10 @@
   DECLARE_CLASS_CUSTOM_ELEMENT_EVENT_TYPE(kAddShortcutCustomEventId);
 
   void BindInterface(
+      mojo::PendingReceiver<password_manager::mojom::PageHandlerFactory>
+          receiver);
+
+  void BindInterface(
       mojo::PendingReceiver<help_bubble::mojom::HelpBubbleHandlerFactory>
           pending_receiver);
 
@@ -65,6 +74,17 @@
   scoped_refptr<extensions::PasswordsPrivateDelegate>
       passwords_private_delegate_;
 
+  // password_manager::mojom::PageHandlerFactory:
+  void CreatePageHandler(
+      mojo::PendingRemote<password_manager::mojom::Page> page,
+      mojo::PendingReceiver<password_manager::mojom::PageHandler> receiver)
+      override;
+
+  std::unique_ptr<PasswordManagerUIHandler> password_manager_ui_handler_;
+
+  mojo::Receiver<password_manager::mojom::PageHandlerFactory>
+      password_manager_page_factory_receiver_{this};
+
   // help_bubble::mojom::HelpBubbleHandlerFactory:
   void CreateHelpBubbleHandler(
       mojo::PendingRemote<help_bubble::mojom::HelpBubbleClient> client,
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui_handler.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui_handler.cc
new file mode 100644
index 0000000..d20ece5
--- /dev/null
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui_handler.cc
@@ -0,0 +1,31 @@
+// 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 "chrome/browser/ui/webui/password_manager/password_manager_ui_handler.h"
+
+#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
+#include "chrome/browser/ui/webui/password_manager/password_manager.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+PasswordManagerUIHandler::PasswordManagerUIHandler(
+    mojo::PendingReceiver<password_manager::mojom::PageHandler> receiver,
+    mojo::PendingRemote<password_manager::mojom::Page> page,
+    scoped_refptr<extensions::PasswordsPrivateDelegate>
+        passwords_private_delegate,
+    content::WebContents* web_contents)
+    : web_contents_(web_contents),
+      passwords_private_delegate_(std::move(passwords_private_delegate)),
+      receiver_(this, std::move(receiver)),
+      page_(std::move(page)) {}
+
+PasswordManagerUIHandler::~PasswordManagerUIHandler() = default;
+
+void PasswordManagerUIHandler::DeleteAllPasswordManagerData(
+    DeleteAllPasswordManagerDataCallback callback) {
+  // TODO(crbug.com/432409279): don't use the delegate, but instead use the
+  // password manager backend directly.
+  passwords_private_delegate_->DeleteAllPasswordManagerData(
+      web_contents_, std::move(callback));
+}
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui_handler.h b/chrome/browser/ui/webui/password_manager/password_manager_ui_handler.h
new file mode 100644
index 0000000..fa521a48
--- /dev/null
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui_handler.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_PASSWORD_MANAGER_PASSWORD_MANAGER_UI_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_PASSWORD_MANAGER_PASSWORD_MANAGER_UI_HANDLER_H_
+
+#include "chrome/browser/ui/webui/password_manager/password_manager.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace extensions {
+class PasswordsPrivateDelegate;
+}
+
+namespace content {
+class WebContents;
+}
+
+class PasswordManagerUIHandler : public password_manager::mojom::PageHandler {
+ public:
+  PasswordManagerUIHandler(
+      mojo::PendingReceiver<password_manager::mojom::PageHandler> receiver,
+      mojo::PendingRemote<password_manager::mojom::Page> page,
+      scoped_refptr<extensions::PasswordsPrivateDelegate>
+          passwords_private_delegate,
+      content::WebContents* web_contents);
+
+  PasswordManagerUIHandler(const PasswordManagerUIHandler&) = delete;
+  PasswordManagerUIHandler& operator=(const PasswordManagerUIHandler&) = delete;
+
+  ~PasswordManagerUIHandler() override;
+
+  // password_manager::mojom::PageHandler:
+  void DeleteAllPasswordManagerData(
+      DeleteAllPasswordManagerDataCallback callback) override;
+
+ private:
+  raw_ptr<content::WebContents> web_contents_;
+  scoped_refptr<extensions::PasswordsPrivateDelegate>
+      passwords_private_delegate_;
+
+  // NOTE: These are located at the end of the list of member variables to
+  // ensure the WebUI page is disconnected before other members are destroyed.
+  mojo::Receiver<password_manager::mojom::PageHandler> receiver_;
+  mojo::Remote<password_manager::mojom::Page> page_;
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_PASSWORD_MANAGER_PASSWORD_MANAGER_UI_HANDLER_H_
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui_handler_unittest.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui_handler_unittest.cc
new file mode 100644
index 0000000..d1b38f15
--- /dev/null
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui_handler_unittest.cc
@@ -0,0 +1,93 @@
+// 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 "chrome/browser/ui/webui/password_manager/password_manager_ui_handler.h"
+
+#include "base/test/test_future.h"
+#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
+#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h"
+#include "chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h"
+#include "chrome/browser/password_manager/password_manager_test_util.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_store/test_password_store.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_web_contents_factory.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+
+class MockPage : public mojom::Page {
+ public:
+  MockPage() = default;
+  ~MockPage() override = default;
+
+  mojo::PendingRemote<mojom::Page> BindAndGetRemote() {
+    DCHECK(!receiver_.is_bound());
+    return receiver_.BindNewPipeAndPassRemote();
+  }
+
+  void FlushForTesting() { receiver_.FlushForTesting(); }
+
+  mojo::Receiver<mojom::Page> receiver_{this};
+};
+
+}  // namespace
+
+class PasswordManagerUIHandlerUnitTest : public testing::Test {
+ public:
+  PasswordManagerUIHandlerUnitTest()
+      : profile_(std::make_unique<TestingProfile>()),
+        web_contents_(factory_.CreateWebContents(profile_.get())) {}
+  ~PasswordManagerUIHandlerUnitTest() override = default;
+
+  void SetUp() override {
+    auto delegate =
+        base::MakeRefCounted<extensions::TestPasswordsPrivateDelegate>();
+    test_delegate_ = delegate.get();
+
+    handler_ = std::make_unique<PasswordManagerUIHandler>(
+        mojo::PendingReceiver<mojom::PageHandler>(),
+        mock_page_.BindAndGetRemote(), std::move(delegate), web_contents_);
+    mock_page_.FlushForTesting();
+    testing::Mock::VerifyAndClearExpectations(&mock_page_);
+  }
+
+  void TearDown() override {
+    test_delegate_ = nullptr;
+    testing::Test::TearDown();
+  }
+
+  PasswordManagerUIHandler& handler() { return *handler_; }
+  extensions::TestPasswordsPrivateDelegate& test_delegate() {
+    return *test_delegate_;
+  }
+
+ protected:
+  raw_ptr<extensions::TestPasswordsPrivateDelegate> test_delegate_;
+
+  // NOTE: The initialization order of these members matters.
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<TestingProfile> profile_;
+  content::TestWebContentsFactory factory_;
+  raw_ptr<content::WebContents> web_contents_;  // Weak. Owned by factory_.
+  testing::NiceMock<MockPage> mock_page_;
+  std::unique_ptr<PasswordManagerUIHandler> handler_;
+};
+
+TEST_F(PasswordManagerUIHandlerUnitTest,
+       DeleteAllPasswordManagerData_CallsDelegate) {
+  base::test::TestFuture<bool> future;
+  EXPECT_FALSE(test_delegate().get_delete_all_password_manager_data_called());
+
+  handler().DeleteAllPasswordManagerData(future.GetCallback());
+
+  EXPECT_TRUE(future.Get());
+  EXPECT_TRUE(test_delegate().get_delete_all_password_manager_data_called());
+}
+
+}  // namespace password_manager
diff --git a/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo.cc b/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo.cc
index 8a2246d..078c8513 100644
--- a/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo.cc
+++ b/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo.cc
@@ -96,8 +96,7 @@
   CHECK(profile_);
   syncer::SyncService* sync_service = GetSyncService(profile_);
   if (!sync_service ||
-      !password_manager::features_util::IsAccountStorageEnabled(
-          profile_->GetPrefs(), sync_service) ||
+      !password_manager::features_util::IsAccountStorageEnabled(sync_service) ||
       !sync_service->IsEngineInitialized()) {
     return false;
   }
diff --git a/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo_unittest.cc b/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo_unittest.cc
index 9eb8cd87..65b0eee7d 100644
--- a/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo_unittest.cc
+++ b/chrome/browser/ui/webui/password_manager/promo_cards/move_passwords_promo_unittest.cc
@@ -57,7 +57,7 @@
   void EnableAccountStorage() {
     fake_sync_service_->SetSignedIn(signin::ConsentLevel::kSignin);
     ASSERT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-        pref_service(), fake_sync_service_.get()));
+        fake_sync_service_.get()));
   }
 
   void SavePassword(password_manager::PasswordForm::Store store_type =
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 13bba35..8aa94e2 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -654,6 +654,9 @@
       {"searchHistory", IDS_SETTINGS_SEARCH_HISTORY},
       {"myActivity", IDS_SETTINGS_MY_ACTIVITY},
       {"manageInYourGoogleAccount", IDS_SETTINGS_MANAGE_IN_YOUR_GOOGLE_ACCOUNT},
+      {"geminiAppsActivity", IDS_SETTINGS_GEMINI_APPS_ACTIVITY},
+      {"manageInYourGeminiAppsActivity",
+       IDS_SETTINGS_MANAGE_IN_YOUR_GEMINI_APPS_ACTIVITY},
       {"deletionConfirmationToast",
        IDS_SETTINGS_DELETION_CONFIRMATION_TOAST_LABEL},
       {"deletionConfirmationAllTimeToast",
@@ -2155,6 +2158,8 @@
                          chrome::kContentSettingsExceptionsLearnMoreURL);
   html_source->AddString("enhancedProtectionHelpCenterURL",
                          chrome::kSafeBrowsingInChromeHelpCenterURL);
+  html_source->AddString("myActivityGeminiAppsUrl",
+                         chrome::kMyActivityGeminiAppsUrl);
 
   // TODO(crbug.com/349860796): Add a learn-more link for HTTPS-First Mode for
   // the new Settings UI, which can be used by the settings-toggle-button.
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 9e88dd9c..3771cf0 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -625,6 +625,10 @@
   html_source->AddBoolean(
       "enableDeleteBrowsingDataRevamp",
       base::FeatureList::IsEnabled(browsing_data::features::kDbdRevampDesktop));
+  html_source->AddBoolean(
+      "enableBrowsingHistoryActorIntegrationM1",
+      base::FeatureList::IsEnabled(
+          browsing_data::features::kBrowsingHistoryActorIntegrationM1));
 
   html_source->AddBoolean(
       "enableSupportForHomeAndWork",
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper.cc b/chrome/browser/ui/webui/settings/site_settings_helper.cc
index 99c0a05a..bc848c39 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper.cc
@@ -261,6 +261,7 @@
     {ContentSettingsType::SUSPICIOUS_NOTIFICATION_IDS, nullptr},
     // TODO(crbug.com/430494524): Implement the WebUI
     {ContentSettingsType::GEOLOCATION_WITH_OPTIONS, nullptr},
+    {ContentSettingsType::DEVICE_ATTRIBUTES, nullptr},
 });
 
 static_assert(
diff --git a/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc b/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc
index bfc474dc..a1cde68 100644
--- a/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc
+++ b/chrome/browser/ui/webui/settings/sync_settings_interactive_uitest.cc
@@ -78,14 +78,14 @@
 
   const DeepQuery turn_off_button_query = {"settings-ui",
                                            "settings-main",
-                                           "settings-basic-page",
+                                           "settings-people-page-index",
                                            "settings-people-page",
                                            "settings-sync-account-control",
                                            "cr-button#signout-button"};
 
   const DeepQuery drop_down_query = {"settings-ui",
                                      "settings-main",
-                                     "settings-basic-page",
+                                     "settings-people-page-index",
                                      "settings-people-page",
                                      "settings-sync-account-control",
                                      "cr-icon-button#dropdown-arrow"};
@@ -139,7 +139,7 @@
   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kHistorySyncOptinDialogContentsId);
   const DeepQuery kTurnHistorySyncOn = {"settings-ui",
                                         "settings-main",
-                                        "settings-basic-page",
+                                        "settings-people-page-index",
                                         "settings-people-page",
                                         "settings-sync-account-control",
                                         "cr-button#sync-button"};
diff --git a/chrome/browser/unexpire_flags.cc b/chrome/browser/unexpire_flags.cc
index da2bed94..6074661 100644
--- a/chrome/browser/unexpire_flags.cc
+++ b/chrome/browser/unexpire_flags.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/unexpire_flags.h"
 
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/containers/flat_map.h"
 #include "base/no_destructor.h"
@@ -33,9 +29,9 @@
     return GetFlagExpirationOverrideMap()->at(flag);
   }
 
-  for (int i = 0; kExpiredFlags[i].name; ++i) {
-    const ExpiredFlag* f = &kExpiredFlags[i];
-    if (strcmp(f->name, flag)) {
+  for (int i = 0; UNSAFE_TODO(kExpiredFlags[i]).name; ++i) {
+    const ExpiredFlag* f = &UNSAFE_TODO(kExpiredFlags[i]);
+    if (UNSAFE_TODO(strcmp(f->name, flag))) {
       continue;
     }
 
@@ -63,7 +59,8 @@
   std::set<int> unexpired;
   for (const auto& f : storage->GetFlags()) {
     int mstone;
-    if (sscanf(f.c_str(), "temporary-unexpire-flags-m%d@1", &mstone) == 1) {
+    if (UNSAFE_TODO(sscanf(f.c_str(), "temporary-unexpire-flags-m%d@1",
+                           &mstone)) == 1) {
       unexpired.insert(mstone);
     }
   }
diff --git a/chrome/browser/user_agent/android_user_agent_browsertest.cc b/chrome/browser/user_agent/android_user_agent_browsertest.cc
index b7240e8c..17d542b0 100644
--- a/chrome/browser/user_agent/android_user_agent_browsertest.cc
+++ b/chrome/browser/user_agent/android_user_agent_browsertest.cc
@@ -10,7 +10,10 @@
 #include "chrome/test/base/chrome_test_utils.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "url/origin.h"
 
 // Browser tests that consider ReduceUserAgentAndroidVersionDeviceModel feature
 // enabled.
@@ -78,3 +81,73 @@
   EXPECT_EQ(GetPlatform(),
             content::EvalJs(GetActiveWebContents(), "navigator.platform"));
 }
+
+// Verifying User-Agent and User-Agent Client Hints on Android.
+class AndroidUserAgentClientHintsBrowserTest
+    : public ReduceUserAgentAndroidPlatformBrowserTest {
+ public:
+  void SetUpOnMainThread() override {
+    AndroidBrowserTest::SetUpOnMainThread();
+    embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  content::EvalJsResult getUserAgentClientHints() {
+    const std::string script = R"(
+      (async () => {
+        const hints = await navigator.userAgentData.getHighEntropyValues([
+          "architecture", "bitness", "formFactors", "fullVersionList",
+          "model", "platformVersion", "uaFullVersion", "wow64"
+        ]);
+        return hints;
+      })()
+    )";
+
+    content::EvalJsResult result =
+        content::EvalJs(GetActiveWebContents(), script);
+    EXPECT_TRUE(result.is_dict());
+    return result;
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AndroidUserAgentClientHintsBrowserTest,
+                       UserAgentAndUserAgentClientHints) {
+  GURL url = embedded_test_server()->GetURL("/simple_page.html");
+  ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), url));
+
+  // 1. Verify the User Agent string.
+  std::string user_agent =
+      content::EvalJs(GetActiveWebContents(), "navigator.userAgent")
+          .ExtractString();
+  EXPECT_THAT(user_agent, testing::HasSubstr("Linux; Android 10; K"));
+
+  // 2. Verify User Agent Client Hints.
+  content::EvalJsResult result = getUserAgentClientHints();
+  const base::Value::Dict& hints = result.ExtractDict();
+
+  // Verify low-entropy client hints.
+  EXPECT_FALSE(hints.Find("brands")->GetList().empty());
+  EXPECT_EQ(hints.Find("platform")->GetString(), "Android");
+  EXPECT_TRUE(hints.Find("mobile")->is_bool());
+
+  // Verify high-entropy client hints.
+  EXPECT_EQ(hints.Find("architecture")->GetString(), "");
+  EXPECT_EQ(hints.Find("bitness")->GetString(), "");
+  EXPECT_FALSE(hints.Find("fullVersionList")->GetList().empty());
+  EXPECT_FALSE(hints.Find("model")->GetString().empty());
+  EXPECT_FALSE(hints.Find("platformVersion")->GetString().empty());
+  EXPECT_FALSE(hints.Find("uaFullVersion")->GetString().empty());
+  EXPECT_FALSE(hints.Find("wow64")->GetBool());
+
+  std::vector<std::string> form_factors;
+  for (const auto& form_factor : hints.Find("formFactors")->GetList()) {
+    if (form_factor.is_string()) {
+      form_factors.push_back(form_factor.GetString());
+    }
+  }
+  EXPECT_EQ(form_factors.size(), 1u);
+  // Expects the default "Desktop" or "Mobile" form factor, it depends on
+  // whether it turns on the command lined switch `kUseMobileUserAgent`.
+  EXPECT_THAT(form_factors[0],
+              testing::AnyOf(testing::Eq("Mobile"), testing::Eq("Desktop")));
+}
diff --git a/chrome/browser/user_education/user_education_configuration_provider.cc b/chrome/browser/user_education/user_education_configuration_provider.cc
index 52903cd..b2efa5f6 100644
--- a/chrome/browser/user_education/user_education_configuration_provider.cc
+++ b/chrome/browser/user_education/user_education_configuration_provider.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 "chrome/browser/user_education/user_education_configuration_provider.h"
 
 #include <algorithm>
diff --git a/chrome/browser/v8_compile_hints/v8_compile_hints_tab_helper.cc b/chrome/browser/v8_compile_hints/v8_compile_hints_tab_helper.cc
index 24d52bab7..e7bbab29 100644
--- a/chrome/browser/v8_compile_hints/v8_compile_hints_tab_helper.cc
+++ b/chrome/browser/v8_compile_hints/v8_compile_hints_tab_helper.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/v8_compile_hints/v8_compile_hints_tab_helper.h"
 
 #include <optional>
 
+#include "base/compiler_specific.h"
 #include "base/feature_list.h"
 #include "base/memory/writable_shared_memory_region.h"
 #include "base/metrics/histogram_functions.h"
@@ -137,7 +133,7 @@
   int64_t* memory = shared_memory_mapping.GetMemoryAs<int64_t>();
 
   for (size_t i = 0; i < kModelInt64Count; ++i) {
-    memory[i] = model.bloom_filter().Get(i);
+    UNSAFE_TODO(memory[i]) = model.bloom_filter().Get(i);
   }
 
   base::ReadOnlySharedMemoryRegion read_only_region =
diff --git a/chrome/browser/web_applications/commands/generated_icon_fix_command.cc b/chrome/browser/web_applications/commands/generated_icon_fix_command.cc
index d57784bc..9de5812 100644
--- a/chrome/browser/web_applications/commands/generated_icon_fix_command.cc
+++ b/chrome/browser/web_applications/commands/generated_icon_fix_command.cc
@@ -76,6 +76,9 @@
   // Set title and start_url for PopulateProductIcons() in case it tries to
   // generate icons again.
   install_info_->title = base::UTF8ToUTF16(app->untranslated_name());
+  // TODO(crbug.com/427566193) : Populate trusted_icons from the app correctly
+  // if the trusted icons are empty.
+  install_info_->trusted_icons = app->trusted_icons();
   for (const apps::IconInfo& icon_info : install_info_->manifest_icons) {
     icon_urls.emplace(IconUrlWithSize::CreateForUnspecifiedSize(icon_info.url));
   }
@@ -102,7 +105,8 @@
 
   // Note: Empty params are noops, WriteData() never deletes icons.
   lock_->icon_manager().WriteData(
-      app_id_, install_info_->icon_bitmaps, /*shortcuts_menu_icons=*/{},
+      app_id_, install_info_->icon_bitmaps, install_info_->trusted_icon_bitmaps,
+      /*shortcuts_menu_icons=*/{},
       /*other_icons_map=*/{},
       base::BindOnce(&GeneratedIconFixCommand::OnIconsWritten,
                      weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/web_applications/commands/manifest_silent_update_command.cc b/chrome/browser/web_applications/commands/manifest_silent_update_command.cc
index 703092e6..5f4f3f8f 100644
--- a/chrome/browser/web_applications/commands/manifest_silent_update_command.cc
+++ b/chrome/browser/web_applications/commands/manifest_silent_update_command.cc
@@ -125,8 +125,9 @@
   }
 
   // TODO(msiem): Detect icon changes.
-  if (pending_update_info.has_name() || pending_update_info.has_short_name() ||
-      !pending_update_info.manifest_icons().empty()) {
+  if (pending_update_info.has_name() ||
+      (!pending_update_info.trusted_icons().empty() &&
+       !pending_update_info.manifest_icons().empty())) {
     return pending_update_info;
   }
   return std::nullopt;
diff --git a/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc
index 494f642..fa83ff20 100644
--- a/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/browser_navigator_iwa_browsertest.cc
@@ -15,6 +15,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/types/expected.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
+#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -145,6 +146,10 @@
   std::unique_ptr<web_app::ScopedBundledIsolatedWebApp> app2_;
 
  private:
+  // TODO(https://crbug.com/423465927): Explore a better approach to make the
+  // existing tests run with the prewarm feature enabled.
+  test::ScopedPrewarmFeatureList scoped_prewarm_feature_list_{
+      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
   base::test::ScopedFeatureList scoped_feature_list_;
   web_app::OsIntegrationManager::ScopedSuppressForTesting os_hooks_suppress_;
 };
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto
index 3de9b36..7cdf76ec 100644
--- a/chrome/browser/web_applications/proto/web_app.proto
+++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -187,8 +187,9 @@
 // the url, size, and purpose must all be populated.
 message PendingUpdateInfo {
   optional string name = 1;
-  optional string short_name = 2;
+  reserved 2;
   repeated sync_pb.WebAppIconInfo manifest_icons = 3;
+  repeated sync_pb.WebAppIconInfo trusted_icons = 4;
 }
 
 // Full WebApp object data. See detailed comments in
diff --git a/chrome/browser/web_applications/test/web_app_icon_test_utils.cc b/chrome/browser/web_applications/test/web_app_icon_test_utils.cc
index fff78bd..d1dc5a18 100644
--- a/chrome/browser/web_applications/test/web_app_icon_test_utils.cc
+++ b/chrome/browser/web_applications/test/web_app_icon_test_utils.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h"
 
 #include <algorithm>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/files/file_enumerator.h"
@@ -131,7 +127,7 @@
 }
 
 base::span<const int> GetIconSizes() {
-  return base::span<const int>(kIconSizes, std::size(kIconSizes));
+  return UNSAFE_TODO(base::span<const int>(kIconSizes, std::size(kIconSizes)));
 }
 
 bool ContainsOneIconOfEachSize(
@@ -268,7 +264,7 @@
   }
 
   base::RunLoop run_loop;
-  icon_manager.WriteData(app_id, std::move(icon_bitmaps), {}, {},
+  icon_manager.WriteData(app_id, std::move(icon_bitmaps), {}, {}, {},
                          base::BindLambdaForTesting([&](bool success) {
                            DCHECK(success);
                            run_loop.Quit();
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 db96c9e..0c714ded 100644
--- a/chrome/browser/web_applications/test/web_app_test_utils.cc
+++ b/chrome/browser/web_applications/test/web_app_test_utils.cc
@@ -615,15 +615,13 @@
 
 std::vector<apps::IconInfo> CreateRandomIconMetadata(RandomHelper& random,
                                                      const GURL& base_url) {
-  const int num_icons = random.next_uint(10);
+  const int num_icons = random.next_uint(10) + 1;
   std::vector<apps::IconInfo> icons(num_icons);
   for (int i = 0; i < num_icons; i++) {
     apps::IconInfo icon;
     icon.url = base_url.Resolve(
         base::StrCat({"/icons", base::NumberToString(random.next_uint())}));
-    if (random.next_bool()) {
-      icon.square_size_px = icon_sizes[random.next_uint(8)];
-    }
+    icon.square_size_px = icon_sizes[random.next_uint(8)];
 
     int purpose = random.next_uint(4);
     if (purpose == 0) {
@@ -1174,39 +1172,18 @@
     if (random.next_bool()) {
       pending_update_info.set_name(name);
     }
-    if (random.next_bool()) {
-      pending_update_info.set_short_name("random_short_name_" + seed_str);
-    }
 
-    if (random.next_bool() || (!pending_update_info.has_name() &&
-                               !pending_update_info.has_short_name())) {
-      const std::vector<int> possible_icon_sizes = {16,  32,  48,  64, 96,
-                                                    128, 192, 256, 512};
-      // Icons to update should not be zero.
-      const int pending_update_icons = random.next_uint(10) + 1;
-      for (int i = 0; i < pending_update_icons; i++) {
-        apps::IconInfo icon;
-        icon.url = params.base_url.Resolve(
-            "/icon" + base::NumberToString(random.next_uint()));
-        size_t random_size_index =
-            random.next_uint() % possible_icon_sizes.size();
-        icon.square_size_px = possible_icon_sizes[random_size_index];
+    if (random.next_bool() || !pending_update_info.has_name()) {
+      std::vector<apps::IconInfo> icons_to_update =
+          CreateRandomIconMetadata(random, params.base_url);
 
-        int purpose = random.next_uint(3);
-        if (purpose == 0) {
-          icon.purpose = apps::IconInfo::Purpose::kAny;
-        }
-        if (purpose == 1) {
-          icon.purpose = apps::IconInfo::Purpose::kMaskable;
-        }
-        if (purpose == 2) {
-          icon.purpose = apps::IconInfo::Purpose::kMonochrome;
-        }
-        sync_pb::WebAppIconInfo* sync_icon =
-            pending_update_info.add_manifest_icons();
-        *sync_icon = AppIconInfoToSyncProto(icon);
+      for (const auto& icon : icons_to_update) {
+        *pending_update_info.add_trusted_icons() = AppIconInfoToSyncProto(icon);
+        *pending_update_info.add_manifest_icons() =
+            AppIconInfoToSyncProto(icon);
       }
     }
+
     app->SetPendingUpdateInfo(pending_update_info);
   }
 
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index 9f04c3b8..e5c860c 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -208,6 +208,24 @@
   }
   return base::Value(std::move(related_applications_json));
 }
+
+void CheckValidPendingUpdateInfo(
+    const std::optional<proto::PendingUpdateInfo>& pending_update_info) {
+  if (pending_update_info.has_value()) {
+    CHECK(pending_update_info->has_name() ||
+          (!pending_update_info->trusted_icons().empty() &&
+           !pending_update_info->manifest_icons().empty()));
+    if (!pending_update_info->trusted_icons().empty() &&
+        !pending_update_info->manifest_icons().empty()) {
+      for (const auto& icon : pending_update_info->trusted_icons()) {
+        CHECK(icon.has_url() && icon.has_size_in_px() && icon.has_purpose());
+      }
+      for (const auto& icon : pending_update_info->manifest_icons()) {
+        CHECK(icon.has_url() && icon.has_size_in_px() && icon.has_purpose());
+      }
+    }
+  }
+}
 }  // namespace
 
 WebApp::CachedDerivedData::CachedDerivedData() = default;
@@ -802,16 +820,7 @@
 
 void WebApp::SetPendingUpdateInfo(
     std::optional<proto::PendingUpdateInfo> pending_update_info) {
-  if (pending_update_info.has_value()) {
-    CHECK(pending_update_info->has_name() ||
-          pending_update_info->has_short_name() ||
-          !pending_update_info->manifest_icons().empty());
-    if (!pending_update_info->manifest_icons().empty()) {
-      for (const auto& icon : pending_update_info->manifest_icons()) {
-        CHECK(icon.has_url() && icon.has_size_in_px() && icon.has_purpose());
-      }
-    }
-  }
+  CheckValidPendingUpdateInfo(pending_update_info);
   pending_update_info_ = std::move(pending_update_info);
 }
 
diff --git a/chrome/browser/web_applications/web_app_database_serialization.cc b/chrome/browser/web_applications/web_app_database_serialization.cc
index 64277f1d..cbd3cd9 100644
--- a/chrome/browser/web_applications/web_app_database_serialization.cc
+++ b/chrome/browser/web_applications/web_app_database_serialization.cc
@@ -1360,17 +1360,33 @@
   web_app->SetRelatedApplications(std::move(related_applications));
 
   if (proto.has_pending_update_info()) {
+    // Exit early if there is a `PendingUpdateInfo` that is completely empty.
     if (!proto.pending_update_info().has_name() &&
-        !proto.pending_update_info().has_short_name() &&
+        proto.pending_update_info().trusted_icons().empty() &&
         proto.pending_update_info().manifest_icons().empty()) {
       return nullptr;
     }
-    if (!proto.pending_update_info().manifest_icons().empty()) {
+
+    // Exit early if trusted icons is populated but manifest icons is not, and
+    // vice versa.
+    if (proto.pending_update_info().trusted_icons().empty() !=
+        proto.pending_update_info().manifest_icons().empty()) {
+      return nullptr;
+    }
+
+    // Populate manifest_icons and trusted_icons only if both are populated.
+    if (!proto.pending_update_info().manifest_icons().empty() &&
+        !proto.pending_update_info().trusted_icons().empty()) {
       for (const auto& icon : proto.pending_update_info().manifest_icons()) {
         if (!icon.has_url() || !icon.has_size_in_px() || !icon.has_purpose()) {
           return nullptr;
         }
       }
+      for (const auto& icon : proto.pending_update_info().trusted_icons()) {
+        if (!icon.has_url() || !icon.has_size_in_px() || !icon.has_purpose()) {
+          return nullptr;
+        }
+      }
     }
     web_app->SetPendingUpdateInfo(proto.pending_update_info());
   }
@@ -1903,12 +1919,16 @@
 
   if (web_app.pending_update_info().has_value()) {
     CHECK(web_app.pending_update_info()->has_name() ||
-          web_app.pending_update_info()->has_short_name() ||
-          !web_app.pending_update_info()->manifest_icons().empty());
-    if (!web_app.pending_update_info()->manifest_icons().empty()) {
+          (!web_app.pending_update_info()->trusted_icons().empty() &&
+           !web_app.pending_update_info()->manifest_icons().empty()));
+    if (!web_app.pending_update_info()->manifest_icons().empty() &&
+        !web_app.pending_update_info()->trusted_icons().empty()) {
       for (const auto& icon : web_app.pending_update_info()->manifest_icons()) {
         CHECK(icon.has_url() && icon.has_size_in_px() && icon.has_purpose());
       }
+      for (const auto& icon : web_app.pending_update_info()->trusted_icons()) {
+        CHECK(icon.has_url() && icon.has_size_in_px() && icon.has_purpose());
+      }
     }
     *local_data->mutable_pending_update_info() = *web_app.pending_update_info();
   }
diff --git a/chrome/browser/web_applications/web_app_database_serialization_unittest.cc b/chrome/browser/web_applications/web_app_database_serialization_unittest.cc
index bf527a1..fd15cd3 100644
--- a/chrome/browser/web_applications/web_app_database_serialization_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_serialization_unittest.cc
@@ -575,17 +575,7 @@
 }
 
 TEST_F(WebAppDatabaseSerializationTest,
-       ParseWebAppProto_HasPendingUpdateInfo_NewShortName) {
-  proto::WebApp proto =
-      CreateWebAppProtoForTesting("Test App", GURL("https://example.com/"));
-  auto* fix = proto.mutable_pending_update_info();
-  fix->set_short_name("Pending Update Short Name");
-
-  EXPECT_THAT(ParseWebAppProto(proto), NotNull());
-}
-
-TEST_F(WebAppDatabaseSerializationTest,
-       ParseWebAppProto_HasPendingUpdateInfo_NewIcon) {
+       ParseWebAppProto_HasPendingUpdateInfo_NewManifestAndTrustedIcon) {
   GURL start_url("https://example.com/");
   proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
   auto* fix = proto.mutable_pending_update_info();
@@ -596,16 +586,23 @@
       sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
   icon1->set_size_in_px(256);
 
+  sync_pb::WebAppIconInfo* icon2 = fix->add_trusted_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
   EXPECT_THAT(ParseWebAppProto(proto), NotNull());
 }
 
 TEST_F(WebAppDatabaseSerializationTest,
-       ParseWebAppProto_InvalidPendingUpdateInfo_MissingIconUrl) {
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingTrustedIcon) {
   GURL start_url("https://example.com/");
   proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
   auto* fix = proto.mutable_pending_update_info();
 
   sync_pb::WebAppIconInfo* icon1 = fix->add_manifest_icons();
+  icon1->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
   icon1->set_purpose(
       sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
   icon1->set_size_in_px(256);
@@ -614,7 +611,42 @@
 }
 
 TEST_F(WebAppDatabaseSerializationTest,
-       ParseWebAppProto_InvalidPendingUpdateInfo_MissingIconPurpose) {
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingManifestIcon) {
+  GURL start_url("https://example.com/");
+  proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
+  auto* fix = proto.mutable_pending_update_info();
+
+  sync_pb::WebAppIconInfo* icon1 = fix->add_trusted_icons();
+  icon1->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon1->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon1->set_size_in_px(256);
+
+  EXPECT_THAT(ParseWebAppProto(proto), IsNull());
+}
+
+TEST_F(WebAppDatabaseSerializationTest,
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingManifestIconUrl) {
+  GURL start_url("https://example.com/");
+  proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
+  auto* fix = proto.mutable_pending_update_info();
+
+  sync_pb::WebAppIconInfo* icon1 = fix->add_manifest_icons();
+  icon1->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon1->set_size_in_px(256);
+
+  sync_pb::WebAppIconInfo* icon2 = fix->add_trusted_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
+  EXPECT_THAT(ParseWebAppProto(proto), IsNull());
+}
+
+TEST_F(WebAppDatabaseSerializationTest,
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingManifestIconPurpose) {
   GURL start_url("https://example.com/");
   proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
   auto* fix = proto.mutable_pending_update_info();
@@ -623,11 +655,17 @@
   icon1->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
   icon1->set_size_in_px(256);
 
+  sync_pb::WebAppIconInfo* icon2 = fix->add_trusted_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
   EXPECT_THAT(ParseWebAppProto(proto), IsNull());
 }
 
 TEST_F(WebAppDatabaseSerializationTest,
-       ParseWebAppProto_InvalidPendingUpdateInfo_MissingIconSizeInPx) {
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingManifestIconSizeInPx) {
   GURL start_url("https://example.com/");
   proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
   auto* fix = proto.mutable_pending_update_info();
@@ -637,6 +675,71 @@
   icon1->set_purpose(
       sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
 
+  sync_pb::WebAppIconInfo* icon2 = fix->add_trusted_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
+  EXPECT_THAT(ParseWebAppProto(proto), IsNull());
+}
+
+TEST_F(WebAppDatabaseSerializationTest,
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingTrustedIconUrl) {
+  GURL start_url("https://example.com/");
+  proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
+  auto* fix = proto.mutable_pending_update_info();
+
+  sync_pb::WebAppIconInfo* icon1 = fix->add_trusted_icons();
+  icon1->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon1->set_size_in_px(256);
+
+  sync_pb::WebAppIconInfo* icon2 = fix->add_manifest_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
+  EXPECT_THAT(ParseWebAppProto(proto), IsNull());
+}
+
+TEST_F(WebAppDatabaseSerializationTest,
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingTrustedIconPurpose) {
+  GURL start_url("https://example.com/");
+  proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
+  auto* fix = proto.mutable_pending_update_info();
+
+  sync_pb::WebAppIconInfo* icon1 = fix->add_trusted_icons();
+  icon1->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon1->set_size_in_px(256);
+
+  sync_pb::WebAppIconInfo* icon2 = fix->add_manifest_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
+  EXPECT_THAT(ParseWebAppProto(proto), IsNull());
+}
+
+TEST_F(WebAppDatabaseSerializationTest,
+       ParseWebAppProto_InvalidPendingUpdateInfo_MissingTrustedIconSizeInPx) {
+  GURL start_url("https://example.com/");
+  proto::WebApp proto = CreateWebAppProtoForTesting("Test App", start_url);
+  auto* fix = proto.mutable_pending_update_info();
+
+  sync_pb::WebAppIconInfo* icon1 = fix->add_trusted_icons();
+  icon1->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon1->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+
+  sync_pb::WebAppIconInfo* icon2 = fix->add_manifest_icons();
+  icon2->set_url(start_url.Resolve(std::string("/icon") + "1000").spec());
+  icon2->set_purpose(
+      sync_pb::WebAppIconInfo_Purpose::WebAppIconInfo_Purpose_ANY);
+  icon2->set_size_in_px(256);
+
   EXPECT_THAT(ParseWebAppProto(proto), IsNull());
 }
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager.cc b/chrome/browser/web_applications/web_app_icon_manager.cc
index f6e62a4..36e3bcb 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager.cc
@@ -67,6 +67,15 @@
 
 using ReadIconCallback = base::OnceCallback<void(SkBitmap)>;
 
+constexpr base::FilePath::CharType kIconsAnyDirectoryName[] =
+    FILE_PATH_LITERAL("Icons");
+constexpr base::FilePath::CharType kIconsMonochromeDirectoryName[] =
+    FILE_PATH_LITERAL("Icons Monochrome");
+constexpr base::FilePath::CharType kIconsMaskableDirectoryName[] =
+    FILE_PATH_LITERAL("Icons Maskable");
+constexpr base::FilePath::CharType kTrustedIconFolderName[] =
+    FILE_PATH_LITERAL("Trusted Icons");
+
 // This utility struct is to carry error logs between threads via return values.
 // If we weren't generating multithreaded errors we would just append the errors
 // to WebAppIconManager::error_log() directly.
@@ -117,12 +126,6 @@
 base::FilePath GetProductIconsDirectory(
     const base::FilePath& app_manifest_resources_directory,
     IconPurpose purpose) {
-  constexpr base::FilePath::CharType kIconsAnyDirectoryName[] =
-      FILE_PATH_LITERAL("Icons");
-  constexpr base::FilePath::CharType kIconsMonochromeDirectoryName[] =
-      FILE_PATH_LITERAL("Icons Monochrome");
-  constexpr base::FilePath::CharType kIconsMaskableDirectoryName[] =
-      FILE_PATH_LITERAL("Icons Maskable");
   switch (purpose) {
     case IconPurpose::ANY:
       return app_manifest_resources_directory.Append(kIconsAnyDirectoryName);
@@ -135,6 +138,19 @@
   }
 }
 
+base::FilePath GetTrustedProductIconsDirectoryRelative(IconPurpose purpose) {
+  base::FilePath trusted_dir(kTrustedIconFolderName);
+  switch (purpose) {
+    case IconPurpose::ANY:
+      return trusted_dir.Append(kIconsAnyDirectoryName);
+    case IconPurpose::MONOCHROME:
+      return trusted_dir.Append(kIconsMonochromeDirectoryName);
+    case IconPurpose::MASKABLE:
+      return trusted_dir.Append(kIconsMaskableDirectoryName);
+  }
+  return trusted_dir;
+}
+
 // This is a private implementation detail of WebAppIconManager, where and how
 // to store shortcuts menu icons files.
 // All of the other shortcut icon directories appear under the directory for
@@ -573,14 +589,15 @@
       base::FilePath&& web_apps_directory,
       webapps::AppId&& app_id,
       IconBitmaps&& icon_bitmaps,
+      IconBitmaps&& trusted_icon_bitmaps,
       ShortcutsMenuIconBitmaps&& shortcuts_menu_icon_bitmaps,
       IconsMap&& other_icons) {
     TRACE_EVENT0("ui",
                  "web_app_icon_manager::WriteIconsJob::WriteIconsBlocking");
-    WriteIconsJob job(std::move(utils), std::move(web_apps_directory),
-                      std::move(app_id), std::move(icon_bitmaps),
-                      std::move(shortcuts_menu_icon_bitmaps),
-                      std::move(other_icons));
+    WriteIconsJob job(
+        std::move(utils), std::move(web_apps_directory), std::move(app_id),
+        std::move(icon_bitmaps), std::move(trusted_icon_bitmaps),
+        std::move(shortcuts_menu_icon_bitmaps), std::move(other_icons));
     return job.Execute();
   }
 
@@ -592,12 +609,14 @@
                 base::FilePath&& web_apps_directory,
                 webapps::AppId&& app_id,
                 IconBitmaps&& icon_bitmaps,
+                IconBitmaps&& trusted_icon_bitmaps,
                 ShortcutsMenuIconBitmaps&& shortcuts_menu_icon_bitmaps,
                 IconsMap&& other_icons)
       : utils_(std::move(utils)),
         web_apps_directory_(std::move(web_apps_directory)),
         app_id_(std::move(app_id)),
         icon_bitmaps_(std::move(icon_bitmaps)),
+        trusted_icon_bitmaps_(std::move(trusted_icon_bitmaps)),
         shortcuts_menu_icon_bitmaps_(std::move(shortcuts_menu_icon_bitmaps)),
         other_icons_(std::move(other_icons)) {}
   ~WriteIconsJob() = default;
@@ -612,6 +631,16 @@
     if (result.HasErrors())
       return result;
 
+    if (!trusted_icon_bitmaps_.empty()) {
+      result = AtomicallyWriteIcons(
+          base::BindRepeating(&WriteIconsJob::WriteTrustedIcons,
+                              base::Unretained(this)),
+          /*subdir_for_icons=*/base::FilePath(kTrustedIconFolderName));
+      if (result.HasErrors()) {
+        return result;
+      }
+    }
+
     if (!shortcuts_menu_icon_bitmaps_.empty()) {
       result = AtomicallyWriteIcons(
           base::BindRepeating(&WriteIconsJob::WriteShortcutsMenuIcons,
@@ -716,8 +745,34 @@
            icon_bitmaps_.GetBitmapsForPurpose(purpose)) {
         TypedResult<bool> write_result =
             EncodeAndWriteIcon(icons_dir, icon_bitmap.second);
-        if (write_result.HasErrors())
+        if (write_result.HasErrors()) {
           return write_result;
+        }
+      }
+    }
+
+    return {.value = true};
+  }
+
+  TypedResult<bool> WriteTrustedIcons(const base::FilePath& base_dir) {
+    TRACE_EVENT0("ui",
+                 "web_app_icon_manager::WriteIconsJob::WriteTrustedIcons");
+    for (IconPurpose purpose : kIconPurposes) {
+      base::FilePath icons_dir =
+          base_dir.Append(GetTrustedProductIconsDirectoryRelative(purpose));
+
+      auto create_result = CreateDirectory(icons_dir);
+      if (create_result.HasErrors()) {
+        return create_result;
+      }
+
+      for (const std::pair<const SquareSizePx, SkBitmap>& icon_bitmap :
+           trusted_icon_bitmaps_.GetBitmapsForPurpose(purpose)) {
+        TypedResult<bool> write_result =
+            EncodeAndWriteIcon(icons_dir, icon_bitmap.second);
+        if (write_result.HasErrors()) {
+          return write_result;
+        }
       }
     }
 
@@ -833,6 +888,7 @@
   base::FilePath web_apps_directory_;
   webapps::AppId app_id_;
   IconBitmaps icon_bitmaps_;
+  IconBitmaps trusted_icon_bitmaps_;
   ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps_;
   SkBitmap home_tab_icon_bitmap_;
   IconsMap other_icons_;
@@ -866,6 +922,7 @@
 void WebAppIconManager::WriteData(
     webapps::AppId app_id,
     IconBitmaps icon_bitmaps,
+    IconBitmaps trusted_icon_bitmaps,
     ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps,
     IconsMap other_icons_map,
     WriteDataCallback callback) {
@@ -877,6 +934,7 @@
       base::BindOnce(
           &WriteIconsJob::WriteIconsBlocking, provider_->file_utils(),
           web_apps_directory_, std::move(app_id), std::move(icon_bitmaps),
+          std::move(trusted_icon_bitmaps),
           std::move(shortcuts_menu_icon_bitmaps), std::move(other_icons_map)),
       base::BindOnce(&LogErrorsCallCallback<bool>, GetWeakPtr(),
                      std::move(callback)));
diff --git a/chrome/browser/web_applications/web_app_icon_manager.h b/chrome/browser/web_applications/web_app_icon_manager.h
index ed69487c..46da968 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.h
+++ b/chrome/browser/web_applications/web_app_icon_manager.h
@@ -60,6 +60,7 @@
   // Writes all data (icons) for an app.
   void WriteData(webapps::AppId app_id,
                  IconBitmaps icon_bitmaps,
+                 IconBitmaps trusted_icon_bitmaps,
                  ShortcutsMenuIconBitmaps shortcuts_menu_icons,
                  IconsMap other_icons_map,
                  WriteDataCallback callback);
diff --git a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
index 81ae2ce..615e0d6 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
@@ -43,6 +43,7 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_scale_factor.h"
 #include "ui/gfx/favicon_size.h"
+#include "ui/gfx/image/image_unittest_util.h"
 
 namespace web_app {
 
@@ -102,8 +103,8 @@
     }
 
     base::RunLoop run_loop;
-    icon_manager().WriteData(app_id, {}, std::move(shortcuts_menu_icons), {},
-                             base::BindLambdaForTesting([&](bool success) {
+    icon_manager().WriteData(app_id, {}, {}, std::move(shortcuts_menu_icons),
+                             {}, base::BindLambdaForTesting([&](bool success) {
                                EXPECT_TRUE(success);
                                run_loop.Quit();
                              }));
@@ -238,6 +239,14 @@
     run_loop.Run();
   }
 
+  base::FilePath GetAppTrustedIconsDir(Profile* profile,
+                                       const webapps::AppId& app_id) {
+    base::FilePath web_apps_root_directory = GetWebAppsRootDirectory(profile);
+    base::FilePath app_dir =
+        GetManifestResourcesDirectoryForApp(web_apps_root_directory, app_id);
+    return app_dir.AppendASCII("Trusted Icons");
+  }
+
   WebAppRegistrar& registrar() { return fake_provider().registrar_unsafe(); }
   WebAppInstallManager& install_manager() {
     return fake_provider().install_manager();
@@ -537,7 +546,7 @@
     base::RunLoop run_loop;
 
     // Overwrite red icons with green and blue ones.
-    icon_manager().WriteData(app_id, std::move(icon_bitmaps), {}, {},
+    icon_manager().WriteData(app_id, std::move(icon_bitmaps), {}, {}, {},
                              base::BindLambdaForTesting([&](bool success) {
                                EXPECT_TRUE(success);
                                run_loop.Quit();
@@ -859,7 +868,7 @@
   AddAppToRegistry(std::move(web_app));
 
   base::RunLoop run_loop;
-  icon_manager().WriteData(app_id, {}, {}, {},
+  icon_manager().WriteData(app_id, {}, {}, {}, {},
                            base::BindLambdaForTesting([&](bool success) {
                              EXPECT_TRUE(success);
                              run_loop.Quit();
@@ -871,11 +880,114 @@
       ReadAllShortcutsMenuIcons(app_id);
   EXPECT_EQ(0u, shortcuts_menu_icons_map.size());
 
+  EXPECT_FALSE(
+      file_utils().PathExists(GetAppTrustedIconsDir(profile(), app_id)));
   EXPECT_FALSE(file_utils().PathExists(GetOtherIconsDir(profile(), app_id)));
   // TODO(estade): check that WebAppIconManager returns no data when other icons
   // are read. (When there is a read function.)
 }
 
+TEST_F(WebAppIconManagerTest, WriteTrustedIconsIntoDisk) {
+  auto web_app = test::CreateWebApp();
+  const webapps::AppId app_id = web_app->app_id();
+  AddAppToRegistry(std::move(web_app));
+
+  IconBitmaps trusted_bitmaps;
+  SkBitmap any_bitmap1 = CreateSquareIcon(icon_size::k32, SK_ColorGREEN);
+  SkBitmap any_bitmap2 = CreateSquareIcon(icon_size::k64, SK_ColorBLUE);
+  SkBitmap any_bitmap3 = CreateSquareIcon(icon_size::k128, SK_ColorYELLOW);
+  trusted_bitmaps.any[icon_size::k32] = any_bitmap1;
+  trusted_bitmaps.any[icon_size::k64] = any_bitmap2;
+  trusted_bitmaps.any[icon_size::k128] = any_bitmap3;
+
+  SkBitmap maskable_bitmap1 = CreateSquareIcon(icon_size::k256, SK_ColorRED);
+  SkBitmap maskable_bitmap2 = CreateSquareIcon(icon_size::k512, SK_ColorCYAN);
+  SkBitmap maskable_bitmap3 = CreateSquareIcon(icon_size::k96, SK_ColorGRAY);
+  trusted_bitmaps.maskable[icon_size::k256] = maskable_bitmap1;
+  trusted_bitmaps.maskable[icon_size::k512] = maskable_bitmap2;
+  trusted_bitmaps.maskable[icon_size::k96] = maskable_bitmap3;
+
+  // Verify writing trusted icons to disk correctly.
+  base::RunLoop run_loop;
+  icon_manager().WriteData(app_id, {}, {trusted_bitmaps}, {}, {},
+                           base::BindLambdaForTesting([&](bool success) {
+                             EXPECT_TRUE(success);
+                             run_loop.Quit();
+                           }));
+  run_loop.Run();
+  EXPECT_TRUE(
+      file_utils().PathExists(GetAppTrustedIconsDir(profile(), app_id)));
+
+  // Verify bitmaps of purpose `any` are written correctly to disk.
+  base::FilePath any_trusted_icons =
+      GetAppTrustedIconsDir(profile(), app_id).AppendASCII("Icons");
+  std::map<SquareSizePx, SkBitmap> any_icons =
+      ReadPngsFromDirectory(&file_utils(), any_trusted_icons);
+  EXPECT_EQ(3u, any_icons.size());
+  gfx::test::AreBitmapsEqual(any_bitmap1, any_icons[icon_size::k32]);
+  gfx::test::AreBitmapsEqual(any_bitmap2, any_icons[icon_size::k64]);
+  gfx::test::AreBitmapsEqual(any_bitmap3, any_icons[icon_size::k128]);
+
+  // Verify bitmaps of purpose `maskable` are written correctly to disk.
+  base::FilePath maskable_trusted_icons =
+      GetAppTrustedIconsDir(profile(), app_id).AppendASCII("Icons Maskable");
+  std::map<SquareSizePx, SkBitmap> maskable_icons =
+      ReadPngsFromDirectory(&file_utils(), maskable_trusted_icons);
+  EXPECT_EQ(3u, any_icons.size());
+  gfx::test::AreBitmapsEqual(maskable_bitmap1, maskable_icons[icon_size::k256]);
+  gfx::test::AreBitmapsEqual(maskable_bitmap2, maskable_icons[icon_size::k512]);
+  gfx::test::AreBitmapsEqual(maskable_bitmap3, maskable_icons[icon_size::k96]);
+}
+
+TEST_F(WebAppIconManagerTest, WriteTrustedAndManifestIconsBoth) {
+  auto web_app = test::CreateWebApp();
+  const webapps::AppId app_id = web_app->app_id();
+  AddAppToRegistry(std::move(web_app));
+
+  IconBitmaps manifest_icons;
+  SkBitmap any_bitmap1 = CreateSquareIcon(icon_size::k32, SK_ColorGREEN);
+  SkBitmap any_bitmap2 = CreateSquareIcon(icon_size::k64, SK_ColorBLUE);
+  manifest_icons.any[icon_size::k64] = any_bitmap1;
+  manifest_icons.any[icon_size::k128] = any_bitmap2;
+
+  IconBitmaps trusted_icons;
+  SkBitmap any_trusted_bitmap1 = CreateSquareIcon(icon_size::k256, SK_ColorRED);
+  SkBitmap any_trusted_bitmap2 =
+      CreateSquareIcon(icon_size::k512, SK_ColorCYAN);
+  trusted_icons.any[icon_size::k256] = any_trusted_bitmap1;
+  trusted_icons.any[icon_size::k512] = any_trusted_bitmap2;
+
+  // Verify writing trusted icons to disk correctly.
+  base::RunLoop run_loop;
+  icon_manager().WriteData(app_id, {manifest_icons}, {trusted_icons}, {}, {},
+                           base::BindLambdaForTesting([&](bool success) {
+                             EXPECT_TRUE(success);
+                             run_loop.Quit();
+                           }));
+  run_loop.Run();
+  EXPECT_TRUE(
+      file_utils().PathExists(GetAppTrustedIconsDir(profile(), app_id)));
+  ASSERT_TRUE(file_utils().PathExists(GetAppIconsAnyDir(profile(), app_id)));
+
+  // Verify bitmaps of purpose `any` are written correctly to disk under the
+  // trusted folder.
+  base::FilePath any_trusted_icons =
+      GetAppTrustedIconsDir(profile(), app_id).AppendASCII("Icons");
+  std::map<SquareSizePx, SkBitmap> any_icons =
+      ReadPngsFromDirectory(&file_utils(), any_trusted_icons);
+  EXPECT_EQ(2u, any_icons.size());
+  gfx::test::AreBitmapsEqual(any_trusted_bitmap1, any_icons[icon_size::k256]);
+  gfx::test::AreBitmapsEqual(any_trusted_bitmap2, any_icons[icon_size::k512]);
+
+  // Verify bitmaps of purpose `any` are written correctly to disk under the
+  // manifest icons folder.
+  std::map<SquareSizePx, SkBitmap> disk_icons = ReadPngsFromDirectory(
+      &file_utils(), GetAppIconsAnyDir(profile(), app_id));
+  EXPECT_EQ(2u, disk_icons.size());
+  gfx::test::AreBitmapsEqual(any_bitmap1, disk_icons[icon_size::k64]);
+  gfx::test::AreBitmapsEqual(any_bitmap2, disk_icons[icon_size::k128]);
+}
+
 TEST_F(WebAppIconManagerTest, WriteOtherIconsToDisk) {
   auto web_app = test::CreateWebApp();
   const webapps::AppId app_id = web_app->app_id();
@@ -886,7 +998,7 @@
   const GURL example_gurl("https://example.com/image.png");
   AddIconToIconsMap(example_gurl, 48, SK_ColorBLUE, &other_icons);
   base::RunLoop run_loop;
-  icon_manager().WriteData(app_id, {}, {}, other_icons,
+  icon_manager().WriteData(app_id, {}, {}, {}, other_icons,
                            base::BindLambdaForTesting([&](bool success) {
                              EXPECT_TRUE(success);
                              run_loop.Quit();
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 761cf3e..6debea2 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -565,10 +565,11 @@
     ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps =
         web_app_info.shortcuts_menu_icon_bitmaps;
     IconsMap other_icon_bitmaps = web_app_info.other_icon_bitmaps;
+    IconBitmaps trusted_icon_bitmaps = web_app_info.trusted_icon_bitmaps;
 
     provider_->icon_manager().WriteData(
-        app_id, std::move(icon_bitmaps), std::move(shortcuts_menu_icon_bitmaps),
-        std::move(other_icon_bitmaps),
+        app_id, std::move(icon_bitmaps), std::move(trusted_icon_bitmaps),
+        std::move(shortcuts_menu_icon_bitmaps), std::move(other_icon_bitmaps),
         std::move(on_icon_write_complete_callback));
   }
 }
diff --git a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
index 630cf1d4..bf2e825 100644
--- a/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
+++ b/chrome/browser/webauthn/enclave_authenticator_browsertest.cc
@@ -103,7 +103,7 @@
 #include "components/trusted_vault/icloud_recovery_key_mac.h"
 #include "components/trusted_vault/proto/vault.pb.h"
 #include "components/trusted_vault/proto_string_bytes_conversion.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/mac/fake_icloud_keychain.h"
 #endif  // BUILDFLAG(IS_MAC)
 
@@ -2847,7 +2847,7 @@
 
 class EnclaveICloudRecoveryKeyTest : public EnclaveAuthenticatorBrowserTest {
  protected:
-  crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_keychain_{
       kICloudKeychainRecoveryKeyAccessGroup};
 };
 
diff --git a/chrome/browser/webauthn/enclave_manager_unittest.cc b/chrome/browser/webauthn/enclave_manager_unittest.cc
index 0977aabd..6a25cd8 100644
--- a/chrome/browser/webauthn/enclave_manager_unittest.cc
+++ b/chrome/browser/webauthn/enclave_manager_unittest.cc
@@ -81,7 +81,7 @@
 
 #if BUILDFLAG(IS_MAC)
 #include "components/trusted_vault/icloud_recovery_key_mac.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/mac/scoped_touch_id_test_environment.h"
 #include "third_party/boringssl/src/include/openssl/hmac.h"
 #include "third_party/boringssl/src/include/openssl/sha.h"
@@ -1834,8 +1834,8 @@
  protected:
   void SetUp() override {
 #if BUILDFLAG(IS_MAC)
-    scoped_fake_apple_keychain_.SetUVMethod(
-        crypto::ScopedFakeAppleKeychainV2::UVMethod::kPasswordOnly);
+    scoped_fake_keychain_.SetUVMethod(
+        crypto::apple::ScopedFakeKeychainV2::UVMethod::kPasswordOnly);
 #endif  // BUILDFLAG(IS_MAC)
   }
 
@@ -1869,7 +1869,7 @@
       fake_provider_;
 
 #if BUILDFLAG(IS_MAC)
-  crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_keychain_{
       "test-keychain-access-group"};
 #endif  // BUILDFLAG(IS_MAC)
 };
@@ -2075,13 +2075,13 @@
   ASSERT_FALSE(manager_.is_idle());
   EXPECT_TRUE(add_future.Wait());
 
-  scoped_fake_apple_keychain_.SetUVMethod(
-      crypto::ScopedFakeAppleKeychainV2::UVMethod::kBiometrics);
+  scoped_fake_keychain_.SetUVMethod(
+      crypto::apple::ScopedFakeKeychainV2::UVMethod::kBiometrics);
   EXPECT_EQ(manager_.uv_key_state(/*platform_has_biometrics=*/true),
             EnclaveManager::UvKeyState::kUsesChromeUI);
 
-  scoped_fake_apple_keychain_.SetUVMethod(
-      crypto::ScopedFakeAppleKeychainV2::UVMethod::kPasswordOnly);
+  scoped_fake_keychain_.SetUVMethod(
+      crypto::apple::ScopedFakeKeychainV2::UVMethod::kPasswordOnly);
   EXPECT_EQ(manager_.uv_key_state(/*platform_has_biometrics=*/false),
             EnclaveManager::UvKeyState::kUsesSystemUI);
 }
diff --git a/chrome/browser/webauthn/local_credential_management_mac_unittest.mm b/chrome/browser/webauthn/local_credential_management_mac_unittest.mm
index ccbadd58..4df532a 100644
--- a/chrome/browser/webauthn/local_credential_management_mac_unittest.mm
+++ b/chrome/browser/webauthn/local_credential_management_mac_unittest.mm
@@ -10,8 +10,8 @@
 #include "build/build_config.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/browser_task_environment.h"
-#include "crypto/apple_keychain_v2.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/mac/authenticator_config.h"
 #include "device/fido/mac/credential_store.h"
 #include "device/fido/public_key_credential_user_entity.h"
@@ -37,7 +37,7 @@
       .keychain_access_group = "test-keychain-access-group",
       .metadata_secret = "TestMetadataSecret"};
   LocalCredentialManagementMac local_cred_man_{config_};
-  crypto::ScopedFakeAppleKeychainV2 keychain_{config_.keychain_access_group};
+  crypto::apple::ScopedFakeKeychainV2 keychain_{config_.keychain_access_group};
   device::fido::mac::TouchIdCredentialStore store_{config_};
 };
 
@@ -172,7 +172,7 @@
   EXPECT_FALSE(future.Get());
 }
 
-class ScopedMockKeychain : crypto::AppleKeychainV2 {
+class ScopedMockKeychain : crypto::apple::KeychainV2 {
  public:
   ScopedMockKeychain() { SetInstanceOverride(this); }
   ~ScopedMockKeychain() override { ClearInstanceOverride(); }
diff --git a/chrome/browser/window_management/window_management_printing_interactive_uitest.cc b/chrome/browser/window_management/window_management_printing_interactive_uitest.cc
index 24a1c4bef..5c1a336 100644
--- a/chrome/browser/window_management/window_management_printing_interactive_uitest.cc
+++ b/chrome/browser/window_management/window_management_printing_interactive_uitest.cc
@@ -56,7 +56,8 @@
 };
 
 // TODO(crbug.com/40115071): Windows crashes static casting to ScreenWin.
-#if BUILDFLAG(IS_WIN)
+// TODO(crbug.com/433855037): Disabling on Mac due to flakiness.
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 #define MAYBE_NoCrashOnEventsDuringHandlerPrint \
   DISABLED_NoCrashOnEventsDuringHandlerPrint
 #else
diff --git a/chrome/browser_exposed_mojom_targets.gni b/chrome/browser_exposed_mojom_targets.gni
index 6b8758d..2cba37c 100644
--- a/chrome/browser_exposed_mojom_targets.gni
+++ b/chrome/browser_exposed_mojom_targets.gni
@@ -48,6 +48,7 @@
   "//chrome/browser/ui/webui/omnibox:mojo_bindings",
   "//chrome/browser/ui/webui/on_device_internals:mojom",
   "//chrome/browser/ui/webui/on_device_translation_internals:mojo_bindings",
+  "//chrome/browser/ui/webui/password_manager:mojo_bindings",
   "//chrome/browser/ui/webui/privacy_sandbox:mojo_bindings",
   "//chrome/browser/ui/webui/reset_password:mojo_bindings",
   "//chrome/browser/ui/webui/search_engine_choice:mojo_bindings",
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index a40dd53..399cdbe 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1753271698-1075c39f3488c88e4997d4ea515b0563194c8b14-faf031012b7e5c3f8eae3fda40f75490f508e42d.profdata
+chrome-android32-main-1753336777-81a094f06ce9f2e45e26aa5b6dcd08a617d4db53-4ae823526fdcef53011f16f07e9ace9c6e70593a.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 06120e9..242ffaf 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1753271227-34947a5a7466727dfd5a7a9b17cf4b43762ad358-959140e823a9fc5e0b2b4f8b9f5f9d9de8bba302.profdata
+chrome-android64-main-1753339875-94d140896db919b8afe164a12bfd35f6b9873e63-bd93898b55bc0a7c7ec0674a108a0b3964176bfa.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index 485a049..74beba88 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1753271698-b035bbc3e0c019f662ece1a7db79ecae82974d46-faf031012b7e5c3f8eae3fda40f75490f508e42d.profdata
+chrome-android-desktop-x64-main-1753336777-276551203ce7418e3b32d9a7d31ef0c17c8d2139-4ae823526fdcef53011f16f07e9ace9c6e70593a.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 5d1aa01e..51ad76f 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1753271698-bd0bac5253c0d5aa4b46f2eb64562c7a832e8571-faf031012b7e5c3f8eae3fda40f75490f508e42d.profdata
+chrome-mac-arm-main-1753336777-56e8c680334431202060ffd302a0253cc81ddf0c-4ae823526fdcef53011f16f07e9ace9c6e70593a.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index a64c5f3..0fb933e 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1753249595-9a4567800831d3a64e5dd9e3a96c3e6f9d4659e9-5ed879ff310879295c274c6e8533187ae364b9df.profdata
+chrome-mac-main-1753336777-89d69827ab98c9d54a6ca739ec564675cb0ade17-4ae823526fdcef53011f16f07e9ace9c6e70593a.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 649b1e40..6ba9f1ab 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1753271698-f862ba900e87b097f4a6b5c1c2cfb204ce347dac-faf031012b7e5c3f8eae3fda40f75490f508e42d.profdata
+chrome-win-arm64-main-1753336777-2f851cc41613bdcc6fa4f44e6af3c5b06814570b-4ae823526fdcef53011f16f07e9ace9c6e70593a.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 9422d37..c994809 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1753249595-4f1eff18f0e77bb42a2fd80db1459e45f8bb3770-5ed879ff310879295c274c6e8533187ae364b9df.profdata
+chrome-win32-main-1753314684-35ef504bcfd964c8692b76560fdea8511850a5b5-701ac6259b6182382cbebd32369b58c64a99d12f.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 66f6252..71ed1d3 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1753261107-12b5fdf38ec94fdfec5d15e8e7c0bd7543bd6c8f-9be55ac20e86efa04ae81e4ea70db4c76b836c5b.profdata
+chrome-win64-main-1753314684-04721f8770c75f2c9f247c8dd591c3efda4071bf-701ac6259b6182382cbebd32369b58c64a99d12f.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 399fda55..5c30fd14 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -556,6 +556,16 @@
                    &kGlicLearnMoreURLConfig,
                    "glic-settings-page-learn-more-url",
                    "");
+BASE_FEATURE_PARAM(std::string,
+                   kGlicExtensionsManagementUrl,
+                   &kGlicLearnMoreURLConfig,
+                   "glic-extensions-management-url",
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+                   "https://gemini.google.com/apps"
+#else
+                   ""
+#endif
+);
 
 BASE_FEATURE(kGlicCSPConfig, "GlicCSPConfig", base::FEATURE_ENABLED_BY_DEFAULT);
 // TODO(crbug.com/378951332): Set appropriate default.
@@ -731,6 +741,10 @@
 BASE_FEATURE(kGlicExtensions,
              "GlicExtensions",
              base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kGlicMultitabUnderlines,
+             "GlicMultitabUnderlines",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
 // Force Privacy Guide to be available even if it would be unavailable
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index e6c63b0c..68710807 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -317,6 +317,8 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<std::string>
     kGlicTabAccessToggleLearnMoreURLDataProtected;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string> kGlicExtensionsManagementUrl;
 
 COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicCSPConfig);
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -425,6 +427,9 @@
 
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kGlicFaviconDataUrls);
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+BASE_DECLARE_FEATURE(kGlicMultitabUnderlines);
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
 COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicExtensions);
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
index 957f213..1c09062f 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
 
 #include <algorithm>
@@ -14,6 +9,7 @@
 #include <tuple>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/field_trial.h"
 #include "base/stl_util.h"
@@ -262,7 +258,7 @@
     const std::string_view unmatched(requested);
     for (const auto& granted : granted_hosts_set) {
       if (granted.size() > 2 && granted[0] == '*' && granted[1] == '.') {
-        const std::string_view stripped_granted(granted.data() + 1,
+        const std::string_view stripped_granted(UNSAFE_TODO(granted.data() + 1),
                                                 granted.length() - 1);
         // If the unmatched host ends with the the granted host,
         // after removing the '*', then it's a match. In addition,
diff --git a/chrome/common/net/x509_certificate_model_unittest.cc b/chrome/common/net/x509_certificate_model_unittest.cc
index a90d317..1fa156c7 100644
--- a/chrome/common/net/x509_certificate_model_unittest.cc
+++ b/chrome/common/net/x509_certificate_model_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/common/net/x509_certificate_model.h"
 
 #include <string_view>
 
+#include "base/compiler_specific.h"
 #include "base/strings/string_view_util.h"
 #include "net/cert/qwac.h"
 #include "net/cert/x509_util.h"
@@ -327,7 +323,7 @@
       0x74, 0x20, 0xa1, 0x20, 0x54, 0x65, 0x78, 0x74};
   builder->SetExtension(
       bssl::der::Input(bssl::kCertificatePoliciesOid),
-      std::string(kExtension, kExtension + sizeof(kExtension)));
+      std::string(kExtension, UNSAFE_TODO(kExtension + sizeof(kExtension))));
 
   x509_certificate_model::X509CertificateModel model(
       bssl::UpRef(builder->GetCertBuffer()));
@@ -510,8 +506,9 @@
       0x63, 0x74, 0x43, 0x52, 0x4c, 0x20, 0x43, 0x41, 0x33, 0x20, 0x63, 0x52,
       0x4c, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72};
 
-  builder->SetExtension(bssl::der::Input(bssl::kCrlDistributionPointsOid),
-                        std::string(kCrldp, kCrldp + sizeof(kCrldp)));
+  builder->SetExtension(
+      bssl::der::Input(bssl::kCrlDistributionPointsOid),
+      std::string(kCrldp, UNSAFE_TODO(kCrldp + sizeof(kCrldp))));
 
   x509_certificate_model::X509CertificateModel model(
       bssl::UpRef(builder->GetCertBuffer()));
@@ -579,8 +576,9 @@
       0x0b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x43, 0x52, 0x4c,
       0x32, 0x81, 0x03, 0x07, 0x9f, 0x80};
 
-  builder->SetExtension(bssl::der::Input(bssl::kCrlDistributionPointsOid),
-                        std::string(kCrldp, kCrldp + sizeof(kCrldp)));
+  builder->SetExtension(
+      bssl::der::Input(bssl::kCrlDistributionPointsOid),
+      std::string(kCrldp, UNSAFE_TODO(kCrldp + sizeof(kCrldp))));
 
   x509_certificate_model::X509CertificateModel model(
       bssl::UpRef(builder->GetCertBuffer()));
@@ -614,7 +612,7 @@
                           0x81, 0x0f, 0x66, 0x6f, 0x6f, 0x40, 0x65, 0x78, 0x61,
                           0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d};
   builder->SetExtension(bssl::der::Input(bssl::kAuthorityInfoAccessOid),
-                        std::string(kAIA, kAIA + sizeof(kAIA)));
+                        std::string(kAIA, UNSAFE_TODO(kAIA + sizeof(kAIA))));
 
   x509_certificate_model::X509CertificateModel model(
       bssl::UpRef(builder->GetCertBuffer()));
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 650b9cb..effcaa3 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -4289,6 +4289,14 @@
 inline constexpr char kServiceWorkerAutoPreloadEnabled[] =
     "worker.service_worker_auto_preload_enabled";
 
+#if !BUILDFLAG(IS_ANDROID)
+// Version string in MAJOR.MINOR.BUILD.PATCH format for the last shown non
+// milestone update toast version. If there's new non milestone update a toast
+// will be shown and this pref will set to the new version.
+inline constexpr char kNonMilestoneUpdateToastVersion[] =
+    "toast.non_milestone_update_toast_version";
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/common/pref_names_util.cc b/chrome/common/pref_names_util.cc
index c02a5e0..064fb74 100644
--- a/chrome/common/pref_names_util.cc
+++ b/chrome/common/pref_names_util.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 "chrome/common/pref_names_util.h"
 
 #include <stddef.h>
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index c2088cb..3ed1cf8 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -385,6 +385,10 @@
 inline constexpr char16_t kMyActivityUrlInClearBrowsingData[] =
     u"https://myactivity.google.com/myactivity?utm_source=chrome_cbd";
 
+// The URL for "Your Gemini Apps Activity" page.
+inline constexpr char16_t kMyActivityGeminiAppsUrl[] =
+    u"https://myactivity.google.com/product/gemini";
+
 // Help URL for the Omnibox setting.
 inline constexpr char16_t kOmniboxLearnMoreURL[] =
 #if BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/installer/mac/keystone_install.sh b/chrome/installer/mac/keystone_install.sh
index a2ef7cd..1820ba98 100755
--- a/chrome/installer/mac/keystone_install.sh
+++ b/chrome/installer/mac/keystone_install.sh
@@ -19,6 +19,9 @@
 #   When set to a non-empty value, the product at this path will be updated.
 #   ksadmin will not be consulted to locate the installed product, nor will it
 #   be called to update any tickets.
+# GOOGLE_CHROME_UPDATER_TEST_ENROLLMENT_PATH
+#   When set to a non-empty value, the installer will search for an enrollment
+#   ticket at this path. Otherwise, the default path will be used.
 #
 # Exit codes:
 #  0  Happiness
@@ -76,6 +79,7 @@
 # system /bin/sh with a newer bash, probably all before SIP became a thing.)
 : ${GOOGLE_CHROME_UPDATER_DEBUG:=}
 : ${GOOGLE_CHROME_UPDATER_TEST_PATH:=}
+: ${GOOGLE_CHROME_UPDATER_TEST_ENROLLMENT_PATH:=}
 
 err() {
   local error="${1}"
@@ -1254,23 +1258,32 @@
   # running for a system or user ticket.
   note "handling brand code"
 
+  local cbcm_path
+  if [[ -n "${GOOGLE_CHROME_UPDATER_TEST_ENROLLMENT_PATH}" ]]; then
+    cbcm_path="${GOOGLE_CHROME_UPDATER_TEST_ENROLLMENT_PATH}"
+  else
+    if [[ -n "${system_ticket}" ]]; then
+      cbcm_path="/Library/Application Support/Google/CloudManagement"
+    else
+      cbcm_path=~/"Library/Application Support/Google/Chrome/Cloud Enrollment"
+    fi
+  fi
+
   local set_brand_file_access=
   local brand_plist
-  local cbcm_path
   if [[ -n "${system_ticket}" ]]; then
     # System ticket.
     set_brand_file_access="y"
     brand_plist="/${UNROOTED_BRAND_PLIST}"
-    cbcm_path="/Library/Application Support/Google/CloudManagement"
   else
     # User ticket.
     brand_plist=~/"${UNROOTED_BRAND_PLIST}"
-    cbcm_path=~"/Library/Application Support/Google/Chrome/Cloud Enrollment"
   fi
   local brand_plist_path="${brand_plist}.plist"
   note "set_brand_file_access = ${set_brand_file_access}"
   note "brand_plist = ${brand_plist}"
   note "brand_plist_path = ${brand_plist_path}"
+  note "cbcm_path = ${cbcm_path}"
 
   # If there is no brand plist in the old browser installation, read the brand
   # from the keystone file.
diff --git a/chrome/installer/mac/keystone_install_unittest.cc b/chrome/installer/mac/keystone_install_unittest.cc
new file mode 100644
index 0000000..e1a89d8
--- /dev/null
+++ b/chrome/installer/mac/keystone_install_unittest.cc
@@ -0,0 +1,309 @@
+// 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 <poll.h>
+
+#include <cstdlib>
+#include <string>
+
+#include "base/apple/foundation_util.h"
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#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/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class KeystoneInstallTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(temp_.CreateUniqueTempDir());
+
+    // Create a fake app bundle
+    mount_dir_ = temp_.GetPath().AppendUTF8("mount");
+    base::CreateDirectory(mount_dir_);
+    base::CreateDirectory(mount_dir_.AppendUTF8("Google Chrome.app")
+                              .AppendUTF8("Contents")
+                              .AppendUTF8("Versions")
+                              .AppendUTF8("1")
+                              .AppendUTF8("Google Chrome Framework.framework")
+                              .AppendUTF8("Resources"));
+    SetInfoPlistItem(mount_dir_, "CFBundleShortVersionString", "1");
+    SetInfoPlistItem(mount_dir_, "KSProductID", "com.google.Chrome");
+    SetInfoPlistItem(mount_dir_, "KSVersion", "2");
+    SetInfoPlistItem(mount_dir_, "KSUpdateURL", "https://example");
+
+    // Create the destination directory.
+    app_install_dir_ = temp_.GetPath().AppendUTF8("dest");
+    base::CreateDirectory(app_install_dir_);
+
+    // Create a fake ksadmin.
+    std::string ksadmin =
+        R"(
+        #!/bin/bash
+        if [ "${1}" = "--ksadmin-version" ] ; then
+          # version check
+          echo "137.0.0.0"
+          exit 0
+        fi
+        if [ "${1}" = "-pP" ] ; then
+          # finding app to update
+          echo " xc=<KSPathExistenceChecker:0x45 path=__DEST__>"
+          exit 0
+        fi
+        # otherwise, just save args
+        while (( "$#" )) ; do
+          echo -n "${1} " >> "__OUTFILE__"
+          shift
+        done
+        echo "\n" >> "__OUTFILE__"
+        exit 0
+        )";
+    base::ReplaceSubstringsAfterOffset(&ksadmin, 0, "__DEST__",
+                                       app_install_dir_.AsUTF8Unsafe());
+    base::ReplaceSubstringsAfterOffset(
+        &ksadmin, 0, "__OUTFILE__",
+        temp_.GetPath().AppendUTF8("ksadmin_out").AsUTF8Unsafe());
+    base::CreateDirectory(temp_.GetPath().AppendUTF8("ksadmin"));
+    ASSERT_TRUE(base::WriteFile(
+        temp_.GetPath().AppendUTF8("ksadmin").AppendUTF8("ksadmin"), ksadmin));
+    ASSERT_TRUE(base::SetPosixFilePermissions(
+        temp_.GetPath().AppendUTF8("ksadmin").AppendUTF8("ksadmin"),
+        base::FILE_PERMISSION_READ_BY_USER |
+            base::FILE_PERMISSION_WRITE_BY_USER |
+            base::FILE_PERMISSION_EXECUTE_BY_USER));
+  }
+
+  // There is no simple API in base/launch.h for providing environment
+  // variables and capturing all of stdout, stderr, and the exit code.
+  void RunExecutable(const base::CommandLine& cmd,
+                     const base::EnvironmentMap& env,
+                     std::string* output,
+                     int* exit_code) {
+    base::ScopedFD read_fd, write_fd;
+    {
+      int pipefds[2] = {};
+      ASSERT_EQ(pipe(pipefds), 0);
+      read_fd.reset(pipefds[0]);
+      write_fd.reset(pipefds[1]);
+    }
+
+    base::LaunchOptions options;
+    options.fds_to_remap.emplace_back(write_fd.get(), STDOUT_FILENO);
+    options.fds_to_remap.emplace_back(write_fd.get(), STDERR_FILENO);
+    options.current_directory = mount_dir_;
+    options.clear_environment = true;
+    options.environment = env;
+    const base::Process proc = base::LaunchProcess(cmd, options);
+    ASSERT_TRUE(proc.IsValid());
+    write_fd.reset();
+
+    base::Time deadline = base::Time::Now() + base::Seconds(60);
+
+    static constexpr size_t kBufferSize = 1024;
+    base::CheckedNumeric<size_t> total_bytes_read = 0;
+    ssize_t read_this_pass = 0;
+    do {
+      struct pollfd fds[1] = {{.fd = read_fd.get(), .events = POLLIN}};
+      int timeout_remaining_ms =
+          static_cast<int>((deadline - base::Time::Now()).InMilliseconds());
+      if (timeout_remaining_ms < 0 || poll(fds, 1, timeout_remaining_ms) != 1) {
+        break;
+      }
+      base::CheckedNumeric<size_t> new_size =
+          base::CheckedNumeric<size_t>(output->size()) +
+          base::CheckedNumeric<size_t>(kBufferSize);
+      if (!new_size.IsValid() || !total_bytes_read.IsValid()) {
+        // Ignore the rest of the output.
+        break;
+      }
+      output->resize(new_size.ValueOrDie());
+      read_this_pass = HANDLE_EINTR(
+          read(read_fd.get(), &(*output)[total_bytes_read.ValueOrDie()],
+               kBufferSize));
+      if (read_this_pass >= 0) {
+        total_bytes_read += base::CheckedNumeric<size_t>(read_this_pass);
+        if (!total_bytes_read.IsValid()) {
+          // Ignore the rest of the output.
+          break;
+        }
+        output->resize(total_bytes_read.ValueOrDie());
+      }
+    } while (read_this_pass > 0);
+
+    ASSERT_TRUE(proc.WaitForExitWithTimeout(
+        std::max(deadline - base::Time::Now(), base::TimeDelta()), exit_code));
+  }
+
+  void RunInstallScript(int exit_code) {
+    base::FilePath ksinstall;
+    ASSERT_TRUE(
+        base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &ksinstall));
+    ksinstall = ksinstall.AppendUTF8("chrome")
+                    .AppendUTF8("installer")
+                    .AppendUTF8("mac")
+                    .AppendUTF8("keystone_install.sh");
+    base::CommandLine cmd(ksinstall);
+    cmd.AppendArgPath(mount_dir_);
+    cmd.AppendArgPath(app_install_dir_);
+    cmd.AppendArg("1.0.0.0");  // Previous version.
+
+    int actual_exit_code = 0;
+    std::string output;
+    RunExecutable(
+        cmd,
+        {
+            {"KS_TICKET_AP", "ap"},
+            {"KS_TICKET_SERVER_URL", "https://exampleserverurl"},
+            {"KS_TICKET_XC_PATH", app_install_dir_.AsUTF8Unsafe()},
+            {"PATH",
+             base::StrCat(
+                 {"/bin:/usr/bin:",
+                  temp_.GetPath().AppendUTF8("ksadmin").AsUTF8Unsafe()})},
+            {"PREVIOUS_VERSION", "1.0.0.0"},
+            {"SERVER_ARGS", ""},
+            {"UPDATE_IS_MACHINE", "0"},
+            {"UNPACK_DIR", mount_dir_.AsUTF8Unsafe()},
+            {"GOOGLE_USAGE_STATS_ENABLED", "0"},
+            {"GOOGLE_CHROME_UPDATER_DEBUG", "1"},
+            {"GOOGLE_CHROME_UPDATER_TEST_ENROLLMENT_PATH",
+             temp_.GetPath().AppendUTF8("Enrollment").AsUTF8Unsafe()},
+        },
+        &output, &actual_exit_code);
+    ASSERT_EQ(actual_exit_code, exit_code) << output;
+  }
+
+  void SetInfoPlistItem(base::FilePath dir,
+                        const std::string& key,
+                        const std::string& value) {
+    SetPlistItem(dir.AppendUTF8("Google Chrome.app")
+                     .AppendUTF8("Contents")
+                     .AppendUTF8("Info"),
+                 key, value);
+  }
+
+  void SetLibraryBrand(const std::string& brand) {
+    SetPlistItem(base::FilePath(getenv("HOME"))
+                     .AppendUTF8("Library")
+                     .AppendUTF8("Google")
+                     .AppendUTF8("Google Chrome Brand"),
+                 "KSBrandID", brand);
+  }
+
+  void SetPlistItem(base::FilePath plist,
+                    const std::string& key,
+                    const std::string& value) {
+    std::string output;
+    base::CommandLine cmd(base::FilePath("defaults"));
+    cmd.AppendArg("write");
+    cmd.AppendArgPath(plist);
+    cmd.AppendArg(key);
+    cmd.AppendArg("-string");
+    cmd.AppendArg(value);
+    ASSERT_TRUE(base::GetAppOutput(cmd, &output)) << output;
+  }
+
+  std::string ReadLibraryBrand() {
+    base::CommandLine cmd(base::FilePath("defaults"));
+    cmd.AppendArg("read");
+    cmd.AppendArgPath(base::FilePath(getenv("HOME"))
+                          .AppendUTF8("Library")
+                          .AppendUTF8("Google")
+                          .AppendUTF8("Google Chrome Brand"));
+    cmd.AppendArg("KSBrandID");
+    std::string output;
+    int exit_code = 0;
+    RunExecutable(cmd, {{"__CFPREFERENCES_AVOID_DAEMON", "1"}}, &output,
+                  &exit_code);
+    EXPECT_EQ(exit_code, 0) << output;
+    return output;
+  }
+
+  std::string GetLastKSAdminArgs() {
+    std::string args;
+    EXPECT_TRUE(base::ReadFileToString(
+        temp_.GetPath().AppendUTF8("ksadmin_out"), &args));
+    return args;
+  }
+
+  void SetEnrolled(bool enroll) {
+    const base::FilePath enrollment = temp_.GetPath().AppendUTF8("Enrollment");
+    if (enroll) {
+      EXPECT_TRUE(base::WriteFile(enrollment,
+                                  "fake from keystone_install_unittest.cc"));
+    } else {
+      EXPECT_TRUE(base::DeleteFile(enrollment));
+    }
+  }
+
+  base::ScopedTempDir temp_;
+  base::FilePath mount_dir_;
+  base::FilePath app_install_dir_;
+};
+
+TEST_F(KeystoneInstallTest, RunScript) {
+  ASSERT_NO_FATAL_FAILURE(RunInstallScript(0));
+}
+
+TEST_F(KeystoneInstallTest, CBCMBrandSubstitution) {
+  SetEnrolled(true);
+  ASSERT_NO_FATAL_FAILURE(SetLibraryBrand("GCEA"));
+  ASSERT_NO_FATAL_FAILURE(RunInstallScript(0));
+  ASSERT_EQ(ReadLibraryBrand(), "GCCA\n");
+}
+
+TEST_F(KeystoneInstallTest, CBCMReverseBrandSubstitution) {
+  SetEnrolled(false);
+  ASSERT_NO_FATAL_FAILURE(SetLibraryBrand("GCCA"));
+  ASSERT_NO_FATAL_FAILURE(RunInstallScript(0));
+  ASSERT_EQ(ReadLibraryBrand(), "GCEA\n");
+}
+
+TEST_F(KeystoneInstallTest, CBCMBrandSubstitutionNoOpGGLS) {
+  SetEnrolled(true);
+  ASSERT_NO_FATAL_FAILURE(SetLibraryBrand("GGLS"));
+  ASSERT_NO_FATAL_FAILURE(RunInstallScript(0));
+  ASSERT_EQ(ReadLibraryBrand(), "GGLS\n");
+}
+
+TEST_F(KeystoneInstallTest, CBCMBrandSubstitutionNoOpGCEA) {
+  SetEnrolled(false);
+  ASSERT_NO_FATAL_FAILURE(SetLibraryBrand("GCEA"));
+  ASSERT_NO_FATAL_FAILURE(RunInstallScript(0));
+  ASSERT_EQ(ReadLibraryBrand(), "GCEA\n");
+}
+
+TEST_F(KeystoneInstallTest, CBCMBrandSubstitutionNoOpGCCA) {
+  SetEnrolled(true);
+  ASSERT_NO_FATAL_FAILURE(SetLibraryBrand("GCCA"));
+  ASSERT_NO_FATAL_FAILURE(RunInstallScript(0));
+  ASSERT_EQ(ReadLibraryBrand(), "GCCA\n");
+}
+
+// keystone_install_test.sh contains a number of tests for keystone_install.sh.
+// They could eventually be migrated to this C++ test fixture, but for now just
+// run the existing script.
+TEST_F(KeystoneInstallTest, RunTestScript) {
+  std::string output;
+  base::FilePath ksinstall_test;
+  ASSERT_TRUE(
+      base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &ksinstall_test));
+  ksinstall_test = ksinstall_test.AppendUTF8("chrome")
+                       .AppendUTF8("installer")
+                       .AppendUTF8("mac")
+                       .AppendUTF8("keystone_install_test.sh");
+  ASSERT_TRUE(
+      base::GetAppOutputAndError(base::CommandLine(ksinstall_test), &output))
+      << output;
+}
+
+}  // namespace
diff --git a/chrome/renderer/bound_session_credentials/bound_session_request_throttled_in_renderer_manager_unittest.cc b/chrome/renderer/bound_session_credentials/bound_session_request_throttled_in_renderer_manager_unittest.cc
index 169f88e..bd4fbdd 100644
--- a/chrome/renderer/bound_session_credentials/bound_session_request_throttled_in_renderer_manager_unittest.cc
+++ b/chrome/renderer/bound_session_credentials/bound_session_request_throttled_in_renderer_manager_unittest.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/renderer/bound_session_credentials/bound_session_request_throttled_in_renderer_manager.h"
 
 #include <memory>
 #include <queue>
 
+#include "base/compiler_specific.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/test/task_environment.h"
@@ -125,7 +121,7 @@
       futures;
 
   for (size_t i = 0; i < futures.size(); ++i) {
-    manager()->HandleRequestBlockedOnCookie(kRequestGURLs[i],
+    manager()->HandleRequestBlockedOnCookie(UNSAFE_TODO(kRequestGURLs[i]),
                                             futures[i].GetCallback());
   }
 
diff --git a/chrome/renderer/extensions/api/chrome_extensions_renderer_api_provider.cc b/chrome/renderer/extensions/api/chrome_extensions_renderer_api_provider.cc
index ebad340..c34ba67 100644
--- a/chrome/renderer/extensions/api/chrome_extensions_renderer_api_provider.cc
+++ b/chrome/renderer/extensions/api/chrome_extensions_renderer_api_provider.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/renderer/extensions/api/chrome_extensions_renderer_api_provider.h"
 
+#include <string_view>
+
 #include "chrome/grit/renderer_resources.h"
 #include "chrome/renderer/extensions/api/extension_hooks_delegate.h"
 #include "chrome/renderer/extensions/api/notifications_native_handler.h"
@@ -114,110 +116,94 @@
 
 void ChromeExtensionsRendererAPIProvider::PopulateSourceMap(
     ResourceBundleSourceMap* source_map) const {
-  // Custom bindings.
-  source_map->RegisterSource("action", IDR_ACTION_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("browserAction",
-                             IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("declarativeContent",
-                             IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("desktopCapture",
-                             IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("developerPrivate",
-                             IDR_DEVELOPER_PRIVATE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("downloads", IDR_DOWNLOADS_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("gcm", IDR_GCM_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("identity", IDR_IDENTITY_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("imageWriterPrivate",
-                             IDR_IMAGE_WRITER_PRIVATE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("mediaGalleries",
-                             IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("notifications",
-                             IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("pageCapture",
-                             IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("syncFileSystem",
-                             IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
+  struct RegisterSourceData {
+    std::string_view name;
+    int resource_id;
+  };
+
+  static constexpr RegisterSourceData kSources[] = {
+      // Custom bindings.
+      {"action", IDR_ACTION_CUSTOM_BINDINGS_JS},
+      {"browserAction", IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS},
+      {"declarativeContent", IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS},
+      {"desktopCapture", IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS},
+      {"developerPrivate", IDR_DEVELOPER_PRIVATE_CUSTOM_BINDINGS_JS},
+      {"downloads", IDR_DOWNLOADS_CUSTOM_BINDINGS_JS},
+      {"gcm", IDR_GCM_CUSTOM_BINDINGS_JS},
+      {"identity", IDR_IDENTITY_CUSTOM_BINDINGS_JS},
+      {"imageWriterPrivate", IDR_IMAGE_WRITER_PRIVATE_CUSTOM_BINDINGS_JS},
+      {"input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS},
+      {"mediaGalleries", IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS},
+      {"notifications", IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS},
+      {"omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS},
+      {"pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS},
+      {"pageCapture", IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS},
+      {"syncFileSystem", IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS},
+      {"tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS},
+      {"tts", IDR_TTS_CUSTOM_BINDINGS_JS},
+      {"ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS},
 
 #if BUILDFLAG(IS_CHROMEOS)
-  source_map->RegisterSource("certificateProvider",
-                             IDR_CERTIFICATE_PROVIDER_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("enterprise.platformKeys",
-                             IDR_ENTERPRISE_PLATFORM_KEYS_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("enterprise.platformKeys.CryptoKey",
-                             IDR_ENTERPRISE_PLATFORM_KEYS_CRYPTO_KEY_JS);
-  source_map->RegisterSource("enterprise.platformKeys.SubtleCrypto",
-                             IDR_ENTERPRISE_PLATFORM_KEYS_SUBTLE_CRYPTO_JS);
-  source_map->RegisterSource("enterprise.platformKeys.Token",
-                             IDR_ENTERPRISE_PLATFORM_KEYS_TOKEN_JS);
-  source_map->RegisterSource("fileBrowserHandler",
-                             IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("fileSystemProvider",
-                             IDR_FILE_SYSTEM_PROVIDER_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("platformKeys",
-                             IDR_PLATFORM_KEYS_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("platformKeys.getCryptoKeyUtil",
-                             IDR_PLATFORM_KEYS_GET_CRYPTO_KEY_UTIL_JS);
-  source_map->RegisterSource("platformKeys.Key", IDR_PLATFORM_KEYS_KEY_JS);
-  source_map->RegisterSource("platformKeys.SubtleCrypto",
-                             IDR_PLATFORM_KEYS_SUBTLE_CRYPTO_JS);
-  source_map->RegisterSource("platformKeys.utils", IDR_PLATFORM_KEYS_UTILS_JS);
+      {"certificateProvider", IDR_CERTIFICATE_PROVIDER_CUSTOM_BINDINGS_JS},
+      {"enterprise.platformKeys",
+       IDR_ENTERPRISE_PLATFORM_KEYS_CUSTOM_BINDINGS_JS},
+      {"enterprise.platformKeys.CryptoKey",
+       IDR_ENTERPRISE_PLATFORM_KEYS_CRYPTO_KEY_JS},
+      {"enterprise.platformKeys.SubtleCrypto",
+       IDR_ENTERPRISE_PLATFORM_KEYS_SUBTLE_CRYPTO_JS},
+      {"enterprise.platformKeys.Token", IDR_ENTERPRISE_PLATFORM_KEYS_TOKEN_JS},
+      {"fileBrowserHandler", IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS},
+      {"fileSystemProvider", IDR_FILE_SYSTEM_PROVIDER_CUSTOM_BINDINGS_JS},
+      {"platformKeys", IDR_PLATFORM_KEYS_CUSTOM_BINDINGS_JS},
+      {"platformKeys.getCryptoKeyUtil",
+       IDR_PLATFORM_KEYS_GET_CRYPTO_KEY_UTIL_JS},
+      {"platformKeys.Key", IDR_PLATFORM_KEYS_KEY_JS},
+      {"platformKeys.SubtleCrypto", IDR_PLATFORM_KEYS_SUBTLE_CRYPTO_JS},
+      {"platformKeys.utils", IDR_PLATFORM_KEYS_UTILS_JS},
 
-  // Remote Apps.
-  source_map->RegisterSource("chromeos.remote_apps.mojom-lite",
-                             IDR_REMOTE_APPS_MOJOM_LITE_JS);
-  source_map->RegisterSource("chromeos.remote_apps",
-                             IDR_REMOTE_APPS_BINDINGS_JS);
-  source_map->RegisterSource("url/mojom/url.mojom-lite",
-                             IDR_MOJO_URL_MOJOM_LITE_JS);
+      // Remote Apps.
+      {"chromeos.remote_apps.mojom-lite", IDR_REMOTE_APPS_MOJOM_LITE_JS},
+      {"chromeos.remote_apps", IDR_REMOTE_APPS_BINDINGS_JS},
+      {"url/mojom/url.mojom-lite", IDR_MOJO_URL_MOJOM_LITE_JS},
 
-  source_map->RegisterSource("fileManagerPrivate",
-                             IDR_FILE_MANAGER_PRIVATE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("terminalPrivate",
-                             IDR_TERMINAL_PRIVATE_CUSTOM_BINDINGS_JS);
+      {"fileManagerPrivate", IDR_FILE_MANAGER_PRIVATE_CUSTOM_BINDINGS_JS},
+      {"terminalPrivate", IDR_TERMINAL_PRIVATE_CUSTOM_BINDINGS_JS},
 
-  // IME service on Chrome OS.
-  source_map->RegisterSource("ash.ime.mojom.ime_service.mojom",
-                             IDR_IME_SERVICE_MOJOM_JS);
-  source_map->RegisterSource("ash.ime.mojom.input_engine.mojom",
-                             IDR_IME_SERVICE_INPUT_ENGINE_MOJOM_JS);
-  source_map->RegisterSource("ash.ime.mojom.input_method.mojom",
-                             IDR_IME_SERVICE_INPUT_METHOD_MOJOM_JS);
-  source_map->RegisterSource("ash.ime.mojom.input_method_host.mojom",
-                             IDR_IME_SERVICE_INPUT_METHOD_HOST_MOJOM_JS);
-  source_map->RegisterSource("chromeos.ime.service",
-                             IDR_IME_SERVICE_BINDINGS_JS);
+      // IME service on Chrome OS.
+      {"ash.ime.mojom.ime_service.mojom", IDR_IME_SERVICE_MOJOM_JS},
+      {"ash.ime.mojom.input_engine.mojom",
+       IDR_IME_SERVICE_INPUT_ENGINE_MOJOM_JS},
+      {"ash.ime.mojom.input_method.mojom",
+       IDR_IME_SERVICE_INPUT_METHOD_MOJOM_JS},
+      {"ash.ime.mojom.input_method_host.mojom",
+       IDR_IME_SERVICE_INPUT_METHOD_HOST_MOJOM_JS},
+      {"chromeos.ime.service", IDR_IME_SERVICE_BINDINGS_JS},
 
-  source_map->RegisterSource("chromeos.tts.mojom.google_tts_stream.mojom",
-                             IDR_GOOGLE_TTS_STREAM_MOJOM_JS);
-  source_map->RegisterSource("chromeos.tts.google_stream",
-                             IDR_GOOGLE_TTS_STREAM_BINDINGS_JS);
+      {"chromeos.tts.mojom.google_tts_stream.mojom",
+       IDR_GOOGLE_TTS_STREAM_MOJOM_JS},
+      {"chromeos.tts.google_stream", IDR_GOOGLE_TTS_STREAM_BINDINGS_JS},
 
-  source_map->RegisterSource("ash.enhanced_network_tts.mojom-lite",
-                             IDR_ENHANCED_NETWORK_TTS_MOJOM_LITE_JS);
-  source_map->RegisterSource("ash.enhanced_network_tts",
-                             IDR_ENHANCED_NETWORK_TTS_BINDINGS_JS);
+      {"ash.enhanced_network_tts.mojom-lite",
+       IDR_ENHANCED_NETWORK_TTS_MOJOM_LITE_JS},
+      {"ash.enhanced_network_tts", IDR_ENHANCED_NETWORK_TTS_BINDINGS_JS},
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-  source_map->RegisterSource(
-      "webrtcDesktopCapturePrivate",
-      IDR_WEBRTC_DESKTOP_CAPTURE_PRIVATE_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("webrtcLoggingPrivate",
-                             IDR_WEBRTC_LOGGING_PRIVATE_CUSTOM_BINDINGS_JS);
+      {"webrtcDesktopCapturePrivate",
+       IDR_WEBRTC_DESKTOP_CAPTURE_PRIVATE_CUSTOM_BINDINGS_JS},
+      {"webrtcLoggingPrivate", IDR_WEBRTC_LOGGING_PRIVATE_CUSTOM_BINDINGS_JS},
 
-  // Platform app sources that are not API-specific..
-  source_map->RegisterSource("chromeWebViewContextMenusApiMethods",
-                             IDR_CHROME_WEB_VIEW_CONTEXT_MENUS_API_METHODS_JS);
-  source_map->RegisterSource("chromeWebViewElement",
-                             IDR_CHROME_WEB_VIEW_ELEMENT_JS);
-  source_map->RegisterSource("chromeWebViewInternal",
-                             IDR_CHROME_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS);
-  source_map->RegisterSource("chromeWebView", IDR_CHROME_WEB_VIEW_JS);
+      // Platform app sources that are not API-specific..
+      {"chromeWebViewContextMenusApiMethods",
+       IDR_CHROME_WEB_VIEW_CONTEXT_MENUS_API_METHODS_JS},
+      {"chromeWebViewElement", IDR_CHROME_WEB_VIEW_ELEMENT_JS},
+      {"chromeWebViewInternal",
+       IDR_CHROME_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS},
+      {"chromeWebView", IDR_CHROME_WEB_VIEW_JS},
+  };
+
+  for (const auto& source : kSources) {
+    source_map->RegisterSource(source.name, source.resource_id);
+  }
 }
 
 void ChromeExtensionsRendererAPIProvider::EnableCustomElementAllowlist() const {
diff --git a/chrome/renderer/resources/controlled_frame/controlled_frame_web_request.js b/chrome/renderer/resources/controlled_frame/controlled_frame_web_request.js
index 164ec4c2..c76f1b1c 100644
--- a/chrome/renderer/resources/controlled_frame/controlled_frame_web_request.js
+++ b/chrome/renderer/resources/controlled_frame/controlled_frame_web_request.js
@@ -189,13 +189,6 @@
     }
     return new WebRequestInterceptor(this.#webRequest, options);
   }
-
-  interceptorBehaviorChanged() {
-    return new $Promise.self((resolve) => {
-      // TODO(crbug.com/421986167): handlerBehaviorChanged is undefined.
-      this.#webRequest.handlerBehaviorChanged(resolve);
-    });
-  }
 }
 
 function createEventInfo(webRequestEventName) {
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
index 5403f27..8f82a2ba 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
@@ -2,16 +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/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h"
 
 #include <memory>
 #include <optional>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/functional/bind.h"
@@ -195,8 +191,8 @@
     std::string model_str = GetFlatBufferString(model_version);
     base::MappedReadOnlyRegion mapped_region =
         base::ReadOnlySharedMemoryRegion::Create(model_str.length());
-    memcpy(mapped_region.mapping.memory(), model_str.data(),
-           model_str.length());
+    UNSAFE_TODO(memcpy(mapped_region.mapping.memory(), model_str.data(),
+                       model_str.length()));
 
     ScorerStorage::GetInstance()->SetScorer(
         Scorer::Create(mapped_region.region.Duplicate(), base::File()));
@@ -477,7 +473,8 @@
   std::string model_str = GetFlatBufferString(0);
   base::MappedReadOnlyRegion mapped_region =
       base::ReadOnlySharedMemoryRegion::Create(model_str.length());
-  memcpy(mapped_region.mapping.memory(), model_str.data(), model_str.length());
+  UNSAFE_TODO(memcpy(mapped_region.mapping.memory(), model_str.data(),
+                     model_str.length()));
   ScorerStorage::GetInstance()->SetScorer(
       Scorer::Create(mapped_region.region.Duplicate(), std::move(file)));
   ASSERT_TRUE(classifier_->is_ready());
diff --git a/chrome/services/file_util/single_file_tar_file_extractor.cc b/chrome/services/file_util/single_file_tar_file_extractor.cc
index ad12ba27..60d3e98 100644
--- a/chrome/services/file_util/single_file_tar_file_extractor.cc
+++ b/chrome/services/file_util/single_file_tar_file_extractor.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/services/file_util/single_file_tar_file_extractor.h"
 
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "chrome/services/file_util/single_file_tar_reader.h"
@@ -71,8 +67,8 @@
   // Returned vector is resized to actual bytes read.
   std::vector<uint8_t> ReadTarFile() {
     std::vector<uint8_t> tar_buffer(kTarBufferSize);
-    const int bytes_read = src_file_.ReadAtCurrentPos(
-        reinterpret_cast<char*>(tar_buffer.data()), kTarBufferSize);
+    const int bytes_read = UNSAFE_TODO(src_file_.ReadAtCurrentPos(
+        reinterpret_cast<char*>(tar_buffer.data()), kTarBufferSize));
 
     if (bytes_read < 0)
       return std::vector<uint8_t>();
diff --git a/chrome/services/file_util/single_file_tar_reader_unittest.cc b/chrome/services/file_util/single_file_tar_reader_unittest.cc
index 01f98ad..792a85c 100644
--- a/chrome/services/file_util/single_file_tar_reader_unittest.cc
+++ b/chrome/services/file_util/single_file_tar_reader_unittest.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/services/file_util/single_file_tar_reader.h"
 
 #include <memory>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/numerics/safe_conversions.h"
@@ -44,8 +40,8 @@
   std::vector<uint8_t> tar_buffer(kTarBufferSize);
   std::vector<uint8_t> contents;
   while (!tar_reader.IsComplete()) {
-    const int bytes_read = src_file.ReadAtCurrentPos(
-        reinterpret_cast<char*>(tar_buffer.data()), tar_buffer.size());
+    const int bytes_read = UNSAFE_TODO(src_file.ReadAtCurrentPos(
+        reinterpret_cast<char*>(tar_buffer.data()), tar_buffer.size()));
     ASSERT_GE(bytes_read, 0);
 
     base::span<const uint8_t> bin_buffer;
@@ -87,8 +83,8 @@
 
   SingleFileTarReader tar_reader;
   std::vector<uint8_t> tar_buffer(kTarBufferSize);
-  const int bytes_read = src_file.ReadAtCurrentPos(
-      reinterpret_cast<char*>(tar_buffer.data()), tar_buffer.size());
+  const int bytes_read = UNSAFE_TODO(src_file.ReadAtCurrentPos(
+      reinterpret_cast<char*>(tar_buffer.data()), tar_buffer.size()));
   ASSERT_GE(bytes_read, 0);
 
   base::span<const uint8_t> bin_buffer;
diff --git a/chrome/services/file_util/single_file_tar_xz_file_extractor.cc b/chrome/services/file_util/single_file_tar_xz_file_extractor.cc
index d51a42b..27641c6 100644
--- a/chrome/services/file_util/single_file_tar_xz_file_extractor.cc
+++ b/chrome/services/file_util/single_file_tar_xz_file_extractor.cc
@@ -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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/services/file_util/single_file_tar_xz_file_extractor.h"
 
 #include <stddef.h>
@@ -17,6 +12,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/numerics/safe_conversions.h"
 #include "chrome/services/file_util/public/mojom/constants.mojom.h"
@@ -50,8 +46,8 @@
   chrome::file_util::mojom::ExtractionResult Extract() {
     std::vector<uint8_t> xz_buffer(kXzBufferSize);
     while (true) {
-      const int bytes_read = src_file_.ReadAtCurrentPos(
-          reinterpret_cast<char*>(xz_buffer.data()), xz_buffer.size());
+      const int bytes_read = UNSAFE_TODO(src_file_.ReadAtCurrentPos(
+          reinterpret_cast<char*>(xz_buffer.data()), xz_buffer.size()));
       if (bytes_read < 0)
         return chrome::file_util::mojom::ExtractionResult::kGenericError;
       if (bytes_read == 0) {
diff --git a/chrome/services/media_gallery_util/public/cpp/local_media_data_source_factory.cc b/chrome/services/media_gallery_util/public/cpp/local_media_data_source_factory.cc
index f016ec8..a6320f3a 100644
--- a/chrome/services/media_gallery_util/public/cpp/local_media_data_source_factory.cc
+++ b/chrome/services/media_gallery_util/public/cpp/local_media_data_source_factory.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/services/media_gallery_util/public/cpp/local_media_data_source_factory.h"
 
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
@@ -51,7 +47,7 @@
   }
 
   auto buffer = std::vector<char>(length);
-  int bytes_read = file.Read(position, buffer.data(), length);
+  int bytes_read = UNSAFE_TODO(file.Read(position, buffer.data(), length));
   if (bytes_read == -1) {
     OnReadComplete(main_task_runner, std::move(cb), false /*success*/,
                    std::vector<char>());
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 6a3137e..4644b35 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -762,7 +762,6 @@
     public_deps += [
       ":test_support_ui_android",
       "//chrome:chrome_android_core",
-      "//chrome/browser/password_manager/android/access_loss:public",
       "//chrome/browser/ui/android/tab_model",
       "//components/feed/core/v2:feed_core_stubs",
     ]
@@ -2410,6 +2409,7 @@
       "//chrome/browser/ui/bluetooth",
       "//chrome/browser/ui/bookmarks:browser_tests",
       "//chrome/browser/ui/browser_window",
+      "//chrome/browser/ui/browser_window:browser_tests",
       "//chrome/browser/ui/color:color_headers",
       "//chrome/browser/ui/content_settings",
       "//chrome/browser/ui/content_settings:browser_tests",
@@ -5461,6 +5461,7 @@
         "//chrome/browser/ui/ash/quick_answers/test:mock_quick_answers_client",
         "//chrome/browser/ui/ash/read_write_cards",
         "//chrome/browser/ui/ash/read_write_cards:read_write_cards_manager",
+        "//chrome/browser/ui/ash/session",
         "//chrome/browser/ui/ash/shelf",
         "//chrome/browser/ui/ash/shelf:test_support",
         "//chrome/browser/ui/ash/system_web_apps",
@@ -5584,6 +5585,7 @@
         "//chromeos/ui/frame:test_support",
         "//chromeos/ui/wm",
         "//components/access_code_cast/common:metrics",
+        "//components/account_id:test_support",
         "//components/app_constants",
         "//components/app_restore",
         "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
@@ -7125,6 +7127,7 @@
     "//components/safe_browsing/content/browser",
     "//components/safe_browsing/content/browser:client_side_detection_images_cache",
     "//components/safe_browsing/content/browser/notification_content_detection",
+    "//components/safe_browsing/content/browser/notification_content_detection:notifications_global_cache_list",
     "//components/safe_browsing/content/browser/notification_content_detection:test_utils",
     "//components/safe_browsing/content/browser/password_protection",
     "//components/safe_browsing/content/browser/password_protection:mock_password_protection",
@@ -7745,7 +7748,6 @@
       "../browser/page_load_metrics/observers/android_page_load_metrics_observer_unittest.cc",
       "../browser/partnerbookmarks/partner_bookmarks_shim_unittest.cc",
       "../browser/password_manager/android/local_passwords_migration_warning_util_unittest.cc",
-      "../browser/password_manager/android/password_access_loss_warning_startup_launcher_unittest.cc",
       "../browser/password_manager/android/password_ui_view_android_unittest.cc",
       "../browser/performance_manager/policies/process_rank_policy_android_unittest.cc",
       "../browser/policy/browser_dm_token_storage_android_unittest.cc",
@@ -7815,8 +7817,6 @@
       "//chrome/browser/password_check/android:unit_tests",
       "//chrome/browser/password_manager/android:unit_tests",
       "//chrome/browser/password_manager/android:utils",
-      "//chrome/browser/password_manager/android/access_loss:test_support",
-      "//chrome/browser/password_manager/android/access_loss:unit_tests",
       "//chrome/browser/password_manager/android/grouped_affiliations:public",
       "//chrome/browser/password_manager/android/grouped_affiliations:test_utils",
       "//chrome/browser/password_manager/android/grouped_affiliations:unit_tests",
@@ -7892,6 +7892,23 @@
       "//ui/events/devices:test_support",
     ]
 
+    if (is_desktop_android) {
+      deps += [
+        # Unit test targets for //chrome/browser/ui/browser_window/internal.
+        #
+        # Note:
+        # Java test support classes must be a *direct* dependency of the
+        # `test()` target. Otherwise, the Java classes can't be found by the
+        # test as they won't be compiled into the test APK.
+        "//chrome/browser/ui/browser_window/internal:unit_tests",
+        "//chrome/browser/ui/browser_window/test:native_unit_test_support_java",
+
+        # Unit test targets for //chrome/browser/ui/android/extensions/windowing/internal.
+        "//chrome/browser/ui/android/extensions/windowing/internal:unit_tests",
+        "//chrome/browser/ui/android/extensions/windowing/test:native_unit_test_support_java",
+      ]
+    }
+
     if (enable_chrome_android_internal) {
       data_deps += [ "//clank/build/bot/filters:unit_tests_filters" ]
     }
@@ -8417,6 +8434,7 @@
       "../browser/new_tab_page/modules/v2/calendar/google_calendar_page_handler_unittest.cc",
       "../browser/new_tab_page/modules/v2/calendar/outlook_calendar_page_handler_unittest.cc",
       "../browser/new_tab_page/modules/v2/most_relevant_tab_resumption/most_relevant_tab_resumption_page_handler_unittest.cc",
+      "../browser/new_tab_page/modules/v2/tab_groups/tab_groups_page_handler_unittest.cc",
       "../browser/search/ntp_features_unittest.cc",
     ]
 
@@ -10040,6 +10058,8 @@
       "../browser/enterprise/connectors/device_trust/key_management/core/persistence:unit_tests",
       "../browser/enterprise/connectors/device_trust/key_management/installer:unit_tests",
       "../browser/enterprise/connectors/device_trust/signals/decorators/browser:unit_tests",
+      "../browser/ui/webui/password_manager:mojo_bindings",
+      "../browser/ui/webui/password_manager:unit_tests",
       "../browser/ui/webui/whats_new:mojo_bindings",
       "//chrome/browser/ui/webui/whats_new:unit_tests",
       "//components/user_education/webui:webui",
@@ -11268,6 +11288,7 @@
       "//chrome/browser/ui/tab_contents",
       "//chrome/browser/ui/tabs:interactive_ui_tests",
       "//chrome/browser/ui/tabs:tab_strip",
+      "//chrome/browser/ui/tabs/alert:interactive_ui_tests",
       "//chrome/browser/ui/thumbnails:interactive_ui_tests",
       "//chrome/browser/ui/toasts",
       "//chrome/browser/ui/toasts:interactive_ui_tests",
@@ -11494,6 +11515,14 @@
       deps += [ "//chrome/browser/smart_card:smart_card" ]
     }
 
+    if (is_mac) {
+      sources += [ "../installer/mac/keystone_install_unittest.cc" ]
+      data += [
+        "//chrome/installer/mac/keystone_install.sh",
+        "//chrome/installer/mac/keystone_install_test.sh",
+      ]
+    }
+
     if (use_ozone) {
       deps += [
         "//ui/ozone",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 0bfb6b0..6586394 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -253,6 +253,7 @@
     "javatests/src/org/chromium/chrome/test/transit/omnibox/OmniboxFacility.java",
     "javatests/src/org/chromium/chrome/test/transit/page/BasePageStation.java",
     "javatests/src/org/chromium/chrome/test/transit/page/CctPageStation.java",
+    "javatests/src/org/chromium/chrome/test/transit/page/CtaPageStation.java",
     "javatests/src/org/chromium/chrome/test/transit/page/FrameInfoUpdatedCondition.java",
     "javatests/src/org/chromium/chrome/test/transit/page/IncognitoWebPageAppMenuFacility.java",
     "javatests/src/org/chromium/chrome/test/transit/page/NativePageCondition.java",
@@ -260,7 +261,6 @@
     "javatests/src/org/chromium/chrome/test/transit/page/PageInteractableOrHiddenCondition.java",
     "javatests/src/org/chromium/chrome/test/transit/page/PageLoadCallbackCondition.java",
     "javatests/src/org/chromium/chrome/test/transit/page/PageLoadedCondition.java",
-    "javatests/src/org/chromium/chrome/test/transit/page/PageStation.java",
     "javatests/src/org/chromium/chrome/test/transit/page/PdfCtaPageStation.java",
     "javatests/src/org/chromium/chrome/test/transit/page/PopupBlockedMessageFacility.java",
     "javatests/src/org/chromium/chrome/test/transit/page/RegularWebPageAppMenuFacility.java",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AutoResetCtaTransitTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AutoResetCtaTransitTestRule.java
index b9592d3..a8668c3 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AutoResetCtaTransitTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/AutoResetCtaTransitTestRule.java
@@ -17,7 +17,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.components.embedder_support.util.UrlConstants;
 
@@ -31,14 +31,15 @@
 @NullMarked
 public class AutoResetCtaTransitTestRule extends BaseCtaTransitTestRule implements TestRule {
     private final BlankCTATabInitialStateRule mInitialStateRule;
-    private final BatchedPublicTransitRule<PageStation> mBatchedRule;
+    private final BatchedPublicTransitRule<CtaPageStation> mBatchedRule;
     private final RuleChain mChain;
 
     /** Create with {@link ChromeTransitTestRules#autoResetCtaActivityRule()}. */
     AutoResetCtaTransitTestRule(boolean clearAllTabState) {
         super();
         mBatchedRule =
-                new BatchedPublicTransitRule<>(PageStation.class, /* expectResetByTest= */ false);
+                new BatchedPublicTransitRule<>(
+                        CtaPageStation.class, /* expectResetByTest= */ false);
         mInitialStateRule = new BlankCTATabInitialStateRule(mActivityTestRule, clearAllTabState);
         mChain =
                 RuleChain.outerRule(mActivityTestRule)
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BaseCtaTransitTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BaseCtaTransitTestRule.java
index ebb4dc4..ab02befb 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BaseCtaTransitTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/BaseCtaTransitTestRule.java
@@ -78,45 +78,45 @@
         mActivityTestRule.assertWaitForPageScaleFactorMatch(expectedScale);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#loadWebPageProgrammatically() or
+    // TODO(crbug.com/406324209): Use CtaPageStation#loadWebPageProgrammatically() or
     // #loadPageProgrammatically to replace these calls.
     public Tab.LoadUrlResult loadUrl(GURL url) {
         return mActivityTestRule.loadUrl(url);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#loadWebPageProgrammatically() or
+    // TODO(crbug.com/406324209): Use CtaPageStation#loadWebPageProgrammatically() or
     // #loadPageProgrammatically to replace these calls.
     public Tab.LoadUrlResult loadUrl(String url) {
         return mActivityTestRule.loadUrl(url);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#loadWebPageProgrammatically() or
+    // TODO(crbug.com/406324209): Use CtaPageStation#loadWebPageProgrammatically() or
     // #loadPageProgrammatically to replace these calls.
     public Tab.LoadUrlResult loadUrl(String url, long secondsToWait) {
         return mActivityTestRule.loadUrl(url, secondsToWait);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#loadWebPageProgrammatically() or
+    // TODO(crbug.com/406324209): Use CtaPageStation#loadWebPageProgrammatically() or
     // #loadPageProgrammatically to replace these calls.
     public Tab.LoadUrlResult loadUrlInTab(
             String url, int pageTransition, Tab tab, long secondsToWait) {
         return mActivityTestRule.loadUrlInTab(url, pageTransition, tab, secondsToWait);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#loadWebPageProgrammatically() or
+    // TODO(crbug.com/406324209): Use CtaPageStation#loadWebPageProgrammatically() or
     // #loadPageProgrammatically to replace these calls.
     public Tab.LoadUrlResult loadUrlInTab(String url, int pageTransition, Tab tab) {
         return mActivityTestRule.loadUrlInTab(url, pageTransition, tab);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#openFakeLinkToWebPage() or #openFakeLink to
+    // TODO(crbug.com/406324209): Use CtaPageStation#openFakeLinkToWebPage() or #openFakeLink to
     // replace these calls.
     public Tab loadUrlInNewTab(String url) {
         return mActivityTestRule.loadUrlInNewTab(url);
     }
 
     // TODO(crbug.com/406324209): Use Public Transit in a case-by-case basis to replace these calls,
-    // often with PageStation#openFakeLinkToWebPage().
+    // often with CtaPageStation#openFakeLinkToWebPage().
     public Tab loadUrlInNewTab(final String url, final boolean incognito) {
         return mActivityTestRule.loadUrlInNewTab(url, incognito);
     }
@@ -126,7 +126,8 @@
         return mActivityTestRule.loadUrlInNewTab(url, incognito, launchType);
     }
 
-    // TODO(crbug.com/406324209): Use PageStation#openNewIncognitoTabFast() to replace these calls.
+    // TODO(crbug.com/406324209): Use CtaPageStation#openNewIncognitoTabFast() to replace these
+    // calls.
     public Tab newIncognitoTabFromMenu() {
         return mActivityTestRule.newIncognitoTabFromMenu();
     }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/FreshCtaTransitTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/FreshCtaTransitTestRule.java
index e6f19ae..5432f17 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/FreshCtaTransitTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/FreshCtaTransitTestRule.java
@@ -18,7 +18,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 
 /**
@@ -45,7 +45,7 @@
     /**
      * Start the test in a blank page.
      *
-     * @return the active entry {@link PageStation}
+     * @return the active entry {@link CtaPageStation}
      */
     public WebPageStation startOnBlankPage() {
         return ChromeTabbedActivityEntryPoints.startOnBlankPage(mActivityTestRule);
@@ -55,7 +55,7 @@
      * Start the test with a url that leads to a web page.
      *
      * @param url the URL of the page to load
-     * @return the active entry {@link PageStation}
+     * @return the active entry {@link CtaPageStation}
      */
     public WebPageStation startOnUrl(String url) {
         return ChromeTabbedActivityEntryPoints.startOnUrl(mActivityTestRule, url);
@@ -76,7 +76,7 @@
      * Start the test in a web page served by the test server.
      *
      * @param relativeUrl the relative URL of the page to serve and load
-     * @return the active entry {@link PageStation}
+     * @return the active entry {@link CtaPageStation}
      */
     public WebPageStation startOnTestServerUrl(String relativeUrl) {
         assert relativeUrl.startsWith("/") : "|relativeUrl| must be relative";
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 5fc298d..0dc924b 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
@@ -23,7 +23,7 @@
 import org.chromium.chrome.test.transit.hub.TabSwitcherGroupCardFacility;
 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.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabThumbnailCondition;
 import org.chromium.chrome.test.util.TabBinningUtil;
@@ -42,7 +42,7 @@
      * Make Chrome have {@code numRegularTabs} of regular Tabs and {@code numIncognitoTabs} of
      * incognito tabs with {@code url} loaded.
      *
-     * @param <T> specific type of PageStation for all opened tabs.
+     * @param <T> specific type of {@link CtaPageStation} for all opened tabs.
      * @param startingStation The current active station.
      * @param numRegularTabs The number of regular tabs.
      * @param numIncognitoTabs The number of incognito tabs.
@@ -50,12 +50,12 @@
      * @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 prepareTabs(
-            PageStation startingStation,
+    public static <T extends CtaPageStation> T prepareTabs(
+            CtaPageStation startingStation,
             int numRegularTabs,
             int numIncognitoTabs,
             String url,
-            Supplier<PageStation.Builder<T>> pageStationFactory) {
+            Supplier<CtaPageStation.Builder<T>> pageStationFactory) {
         List<String> regularTabs = getListOfIdenticalUrls(numRegularTabs, url);
         List<String> incognitoTabs = getListOfIdenticalUrls(numIncognitoTabs, url);
 
@@ -68,15 +68,15 @@
     }
 
     /**
-     * Same as {@link #prepareTabs(PageStation, int, int, String, Supplier)}, but ensures tab
+     * Same as {@link #prepareTabs(CtaPageStation, int, int, String, Supplier)}, but ensures tab
      * thumbnails are captured to disk.
      */
-    public static <T extends PageStation> T prepareTabsWithThumbnails(
-            PageStation startingStation,
+    public static <T extends CtaPageStation> T prepareTabsWithThumbnails(
+            CtaPageStation startingStation,
             int numRegularTabs,
             int numIncognitoTabs,
             String url,
-            Supplier<PageStation.Builder<T>> pageStationFactory) {
+            Supplier<CtaPageStation.Builder<T>> pageStationFactory) {
         List<String> regularTabs = getListOfIdenticalUrls(numRegularTabs, url);
         List<String> incognitoTabs = getListOfIdenticalUrls(numIncognitoTabs, url);
 
@@ -107,19 +107,19 @@
     /**
      * Create {@code numTabs} of {@link Tab}s with {@code url} loaded to Chrome.
      *
-     * @param <T> specific type of PageStation for all opened tabs.
+     * @param <T> specific type of {@link CtaPageStation} for all opened tabs.
      * @param startingPage The current active station.
      * @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.
+     * @return the last opened tab's {@link CtaPageStation}.
      */
     @SuppressWarnings("unused")
-    private static <T extends PageStation> T createTabs(
-            final PageStation startingPage,
+    private static <T extends CtaPageStation> T createTabs(
+            final CtaPageStation startingPage,
             List<String> urls,
             boolean isIncognito,
-            Supplier<PageStation.Builder<T>> pageStationFactory) {
+            Supplier<CtaPageStation.Builder<T>> pageStationFactory) {
         return doCreateTabs(
                 startingPage,
                 urls,
@@ -129,12 +129,12 @@
     }
 
     /** Creates identical tabs and ensures tab thumbnails are captured to disk. */
-    public static <T extends PageStation> T createTabsWithThumbnails(
-            final PageStation startingPage,
+    public static <T extends CtaPageStation> T createTabsWithThumbnails(
+            final CtaPageStation startingPage,
             int numTabs,
             String url,
             boolean isIncognito,
-            Supplier<PageStation.Builder<T>> pageStationFactory) {
+            Supplier<CtaPageStation.Builder<T>> pageStationFactory) {
         List<String> urls = getListOfIdenticalUrls(numTabs, url);
         return doCreateTabs(
                 startingPage, urls, isIncognito, pageStationFactory, /* captureThumbnails= */ true);
@@ -142,7 +142,7 @@
 
     /** Open and display multiple web pages in regular tabs, return the last page. */
     public static WebPageStation createRegularTabsWithWebPages(
-            final PageStation startingPage, List<String> urls) {
+            final CtaPageStation startingPage, List<String> urls) {
         return doCreateTabs(
                 startingPage,
                 urls,
@@ -153,7 +153,7 @@
 
     /** Open and display multiple web pages in incognito tabs, return the last page. */
     public static WebPageStation createIncognitoTabsWithWebPages(
-            final PageStation startingPage, List<String> urls) {
+            final CtaPageStation startingPage, List<String> urls) {
         return doCreateTabs(
                 startingPage,
                 urls,
@@ -163,11 +163,11 @@
     }
 
     // TODO(crbug.com/411430975): Open all tabs at once instead of one by one.
-    private static <T extends PageStation> T doPrepareTabs(
-            PageStation startingStation,
+    private static <T extends CtaPageStation> T doPrepareTabs(
+            CtaPageStation startingStation,
             List<String> urlsForRegularTabs,
             List<String> urlsForIncognitoTabs,
-            Supplier<PageStation.Builder<T>> pageStationFactory,
+            Supplier<CtaPageStation.Builder<T>> pageStationFactory,
             boolean captureThumbnails) {
         assert urlsForRegularTabs.size() >= 1;
         TabModelSelector tabModelSelector = startingStation.getTabModelSelector();
@@ -202,20 +202,20 @@
         return station;
     }
 
-    private static <T extends PageStation> T doCreateTabs(
-            final PageStation startingPage,
+    private static <T extends CtaPageStation> T doCreateTabs(
+            final CtaPageStation startingPage,
             List<String> urls,
             boolean isIncognito,
-            Supplier<PageStation.Builder<T>> pageStationFactory,
+            Supplier<CtaPageStation.Builder<T>> pageStationFactory,
             boolean captureThumbnails) {
         assert !urls.isEmpty();
 
         TabModelSelector tabModelSelector = startingPage.getTabModelSelector();
 
-        PageStation currentPage = startingPage;
+        CtaPageStation currentPage = startingPage;
         for (int i = 0; i < urls.size(); i++) {
             String url = urls.get(i);
-            PageStation previousPage = currentPage;
+            CtaPageStation previousPage = currentPage;
             Tab previousTab = previousPage.loadedTabElement.get();
             if (i == 0 && startingPage.isIncognito() && !isIncognito) {
                 currentPage =
@@ -253,8 +253,8 @@
                         previousTab.getId());
 
                 Tab tabToComeBackTo = currentPage.loadedTabElement.get();
-                PageStation previousPageAgain =
-                        currentPage.selectTabFast(previousTab, PageStation::newGenericBuilder);
+                CtaPageStation previousPageAgain =
+                        currentPage.selectTabFast(previousTab, CtaPageStation::newGenericBuilder);
                 currentPage = previousPageAgain.selectTabFast(tabToComeBackTo, pageStationFactory);
 
                 noopTo().waitFor(
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/edge_to_edge/ViewportFitCoverPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/edge_to_edge/ViewportFitCoverPageStation.java
index c3beec1b..a89e9a385 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/edge_to_edge/ViewportFitCoverPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/edge_to_edge/ViewportFitCoverPageStation.java
@@ -15,7 +15,7 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.transit.edge_to_edge.EdgeToEdgeConditions.BottomControlsStackerCondition;
 import org.chromium.chrome.test.transit.edge_to_edge.EdgeToEdgeConditions.EdgeToEdgeControllerCondition;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.content_public.browser.test.transit.HtmlElement;
 import org.chromium.content_public.browser.test.transit.HtmlElementSpec;
@@ -63,7 +63,7 @@
 
     /** Load the test page viewport-fit-cover-sub-frames-main.html. */
     public static ViewportFitCoverPageStation loadViewportFitCoverPage(
-            ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
+            ChromeTabbedActivityTestRule activityTestRule, CtaPageStation currentPageStation) {
         String url = activityTestRule.getTestServer().getURL(PATH_VIEWPORT_FIT_COVER_SUB_FRAMES);
         return currentPageStation.loadPageProgrammatically(
                 url, new Builder<>(ViewportFitCoverPageStation::new));
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HistoryPaneStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HistoryPaneStation.java
index 80921fed..0cb9f43 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HistoryPaneStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/HistoryPaneStation.java
@@ -19,7 +19,7 @@
 import org.chromium.chrome.browser.history.HistoryItemView;
 import org.chromium.chrome.browser.hub.PaneId;
 import org.chromium.chrome.test.R;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 
 /** The History pane station. */
@@ -99,7 +99,7 @@
         }
 
         /** Select the entry to open. */
-        public WebPageStation selectToOpenWebPage(PageStation previousPage, String url) {
+        public WebPageStation selectToOpenWebPage(CtaPageStation previousPage, String url) {
             return itemElement
                     .clickTo()
                     .arriveAt(
@@ -119,7 +119,7 @@
         }
 
         public void typeSearchTerm(String text) {
-            editTextElement.getTypeTextTrigger(text).triggerTransition();
+            editTextElement.typeTextTo(text).executeTriggerWithoutTransition();
         }
     }
 }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupColorPickerFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupColorPickerFacility.java
index d517119b..36b7c79 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupColorPickerFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupColorPickerFacility.java
@@ -17,13 +17,14 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.test.R;
 import org.chromium.chrome.test.transit.ChromeActivityTabModelBoundStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.components.tab_groups.TabGroupColorId;
 
 /**
  * The color picker palette that is opened from the {@link TabGroupDialogFacility}.
  *
- * @param <HostStationT> the station where the Tab Group Dialog is opened from. Should be
- *     TabSwitcherStation or PageStation.
+ * @param <HostStationT> the station where the Tab Group Dialog is opened from. Should be {@link
+ *     TabSwitcherStation} or {@link CtaPageStation}.
  */
 public class TabGroupColorPickerFacility<
                 HostStationT extends ChromeActivityTabModelBoundStation<ChromeTabbedActivity>>
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java
index 63b338f..1e2f9df 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabGroupDialogFacility.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.test.transit.ChromeActivityTabModelBoundStation;
 import org.chromium.chrome.test.transit.ntp.IncognitoNewTabPageStation;
 import org.chromium.chrome.test.transit.ntp.RegularNewTabPageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabGroupUtil;
 import org.chromium.components.tab_groups.TabGroupColorId;
 
@@ -38,8 +39,8 @@
  * Dialog that appears when a tab group is clicked on in the Tab Switcher or when the tab group
  * snackbar is expanded.
  *
- * @param <HostStationT> the station where the Tab Group Dialog is opened from. Should be
- *     TabSwitcherStation or PageStation.
+ * @param <HostStationT> the station where the Tab Group Dialog is opened from. Should be {@link
+ *     TabSwitcherStation} or {@link CtaPageStation}.
  */
 public class TabGroupDialogFacility<
                 HostStationT extends ChromeActivityTabModelBoundStation<ChromeTabbedActivity>>
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
index c0285b7..66ea139f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
@@ -35,7 +35,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabGridView;
 import org.chromium.chrome.test.R;
 import org.chromium.chrome.test.transit.SoftKeyboardFacility;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabCountChangedCondition;
 import org.chromium.chrome.test.util.TabBinningUtil;
 
@@ -105,11 +105,12 @@
 
     /**
      * @param index The tab index to select.
-     * @param destinationBuilder Builder for the specific type of PageStation expected to appear.
-     * @return Builder of the {@link PageStation} for the tab that was selected.
+     * @param destinationBuilder Builder for the specific type of {@link CtaPageStation} expected to
+     *     appear.
+     * @return Builder of the {@link CtaPageStation} for the tab that was selected.
      */
-    public <T extends PageStation> T selectTabAtIndex(
-            int index, PageStation.Builder<T> destinationBuilder) {
+    public <T extends CtaPageStation> T selectTabAtIndex(
+            int index, CtaPageStation.Builder<T> destinationBuilder) {
         recheckActiveConditions();
 
         return selectTabAtCardIndexTo(index)
@@ -183,11 +184,12 @@
     /**
      * Returns to the previous tab via the back button.
      *
-     * @param destinationBuilder Builder for the specific type of PageStation expected to appear.
-     * @return the {@link PageStation} that Hub returned to.
+     * @param destinationBuilder Builder for the specific type of {@link CtaPageStation} expected to
+     *     appear.
+     * @return the {@link CtaPageStation} that Hub returned to.
      */
-    public <T extends PageStation> T leaveHubToPreviousTabViaBack(
-            PageStation.Builder<T> destinationBuilder) {
+    public <T extends CtaPageStation> T leaveHubToPreviousTabViaBack(
+            CtaPageStation.Builder<T> destinationBuilder) {
         T destination =
                 destinationBuilder.initSelectingExistingTab().withIncognito(mIsIncognito).build();
         return pressBackTo().withRetry().arriveAt(destination);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherTabCardFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherTabCardFacility.java
index ca5329b..28a5576 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherTabCardFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherTabCardFacility.java
@@ -9,7 +9,7 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.test.transit.ViewElement;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 
 /** Represents a non-grouped tab card in the Tab Switcher. */
 public class TabSwitcherTabCardFacility extends TabSwitcherCardFacility {
@@ -28,8 +28,8 @@
     }
 
     /** Clicks the tab card to show the page. */
-    public <PageStationT extends PageStation> PageStationT clickCard(
-            PageStation.Builder<PageStationT> destinationBuilder) {
+    public <PageStationT extends CtaPageStation> PageStationT clickCard(
+            CtaPageStation.Builder<PageStationT> destinationBuilder) {
         boolean isSelecting = mHostStation.getActivity().getActivityTab().getId() == mTabId;
         PageStationT destination =
                 destinationBuilder
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/IncognitoNewTabPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/IncognitoNewTabPageStation.java
index f36833f8..91201b16 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/IncognitoNewTabPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/IncognitoNewTabPageStation.java
@@ -21,12 +21,12 @@
 import org.chromium.chrome.test.transit.SoftKeyboardFacility;
 import org.chromium.chrome.test.transit.omnibox.FakeOmniboxSuggestions;
 import org.chromium.chrome.test.transit.omnibox.OmniboxFacility;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.NativePageCondition;
-import org.chromium.chrome.test.transit.page.PageStation;
 import org.chromium.components.embedder_support.util.UrlConstants;
 
 /** The Incognito New Tab Page screen, with text about Incognito mode. */
-public class IncognitoNewTabPageStation extends PageStation {
+public class IncognitoNewTabPageStation extends CtaPageStation {
     public ViewElement<UrlBar> urlBarElement;
     public ViewElement<View> iconElement;
     public ViewElement<View> goneIncognitoTextElement;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtRemovedSnackbarFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtRemovedSnackbarFacility.java
index d3522f1..17ae4aa 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtRemovedSnackbarFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtRemovedSnackbarFacility.java
@@ -25,7 +25,7 @@
         var mvtsAfterUndo = new MvtsFacility(mMvtsBeforeRemoval.getSiteSuggestions());
         return runTo(
                         () -> {
-                            buttonElement.getClickTrigger().triggerTransition();
+                            buttonElement.clickTo().executeTriggerWithoutTransition();
                             ThreadUtils.runOnUiThreadBlocking(
                                     () ->
                                             fakeMostVisitedSites.setTileSuggestions(
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java
index c6db084..8c2f23f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java
@@ -21,8 +21,8 @@
 import org.chromium.chrome.test.transit.SoftKeyboardFacility;
 import org.chromium.chrome.test.transit.omnibox.FakeOmniboxSuggestions;
 import org.chromium.chrome.test.transit.omnibox.OmniboxFacility;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.NativePageCondition;
-import org.chromium.chrome.test.transit.page.PageStation;
 import org.chromium.components.embedder_support.util.UrlConstants;
 
 import java.util.Collections;
@@ -33,7 +33,7 @@
  * The New Tab Page screen, with an omnibox, most visited tiles, and the Feed instead of the
  * WebContents.
  */
-public class RegularNewTabPageStation extends PageStation {
+public class RegularNewTabPageStation extends CtaPageStation {
     public ViewElement<View> searchBoxElement;
     public ViewElement<UrlBar> urlBarElement;
     public ViewElement<View> logoElement;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/omnibox/OmniboxFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/omnibox/OmniboxFacility.java
index 6c9bc7d..dd4b9d1c 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/omnibox/OmniboxFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/omnibox/OmniboxFacility.java
@@ -17,11 +17,11 @@
 import org.chromium.base.test.transit.ViewSpec;
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.test.R;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.components.browser_ui.widget.scrim.ScrimView;
 
 /** Represents the Omnibox focused state showing the URL bar and accepting keyboard input. */
-public class OmniboxFacility extends Facility<PageStation> {
+public class OmniboxFacility extends Facility<CtaPageStation> {
     public static final ViewSpec<View> STATUS_ICON =
             viewSpec(withId(R.id.location_bar_status_icon));
     public static final ViewSpec<UrlBar> URL_FIELD = viewSpec(UrlBar.class, withId(R.id.url_bar));
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/BasePageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/BasePageStation.java
index 058e5f2..156c76b5 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/BasePageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/BasePageStation.java
@@ -30,8 +30,9 @@
 import java.util.function.Function;
 
 /**
- * Base class for the screen that shows a web or native page in ChromeActivity. {@link PageStation}
- * subclasses this for ChromeTabbedActivity and {@link CctPageStation} for CustomTabActivity.
+ * Base class for the screen that shows a web or native page in ChromeActivity. {@link
+ * CtaPageStation} subclasses this for ChromeTabbedActivity and {@link CctPageStation} for
+ * CustomTabActivity.
  *
  * <p>Contains extra configurable Conditions such as waiting for a tab to be created, selected, have
  * the expected title, etc.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/CtaPageStation.java
similarity index 91%
rename from chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java
rename to chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/CtaPageStation.java
index c9d2525d..eb83266 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/CtaPageStation.java
@@ -41,23 +41,20 @@
  *
  * <p>Contains extra configurable Conditions such as waiting for a tab to be created, selected, have
  * the expected title, etc.
- *
- * <p>TODO(crbug.com/420471518): Rename this to CtaPageStation to match {@link CctPageStation}.
- * Then, rename {@link BasePageStation} to {@link PageStation}.
  */
-public class PageStation extends BasePageStation<ChromeTabbedActivity> {
+public class CtaPageStation extends BasePageStation<ChromeTabbedActivity> {
     public static final ViewSpec<UrlBar> URL_BAR = viewSpec(UrlBar.class, withId(R.id.url_bar));
     public ViewElement<ToolbarControlContainer> toolbarElement;
     public ViewElement<ToggleTabStackButton> tabSwitcherButtonElement;
     public ViewElement<ImageButton> menuButtonElement;
 
-    /** Prefer the PageStation's subclass |newBuilder()|. */
-    public static Builder<PageStation> newGenericBuilder() {
-        return new Builder<>(PageStation::new);
+    /** Prefer the CtaPageStation's subclass |newBuilder()|. */
+    public static Builder<CtaPageStation> newGenericBuilder() {
+        return new Builder<>(CtaPageStation::new);
     }
 
-    /** Use the PageStation's subclass |newBuilder()|. */
-    protected PageStation(Config config) {
+    /** Use the CtaPageStation's subclass |newBuilder()|. */
+    protected CtaPageStation(Config config) {
         super(ChromeTabbedActivity.class, config);
 
         declareEnterCondition(
@@ -92,7 +89,7 @@
     }
 
     /** Opens the app menu by pressing the toolbar "..." button */
-    public PageAppMenuFacility<PageStation> openGenericAppMenu() {
+    public PageAppMenuFacility<CtaPageStation> openGenericAppMenu() {
         recheckActiveConditions();
 
         return menuButtonElement.clickTo().enterFacility(new PageAppMenuFacility<>());
@@ -114,7 +111,7 @@
     }
 
     /** Shortcut to select a different tab programmatically. */
-    public <T extends PageStation> T selectTabFast(
+    public <T extends CtaPageStation> T selectTabFast(
             Tab tabToSelect, Supplier<Builder<T>> pageStationFactory) {
         return runOnUiThreadTo(
                         () ->
@@ -168,7 +165,7 @@
     }
 
     /** Loads a |url| in another tab as if a link was clicked and waits to transition. */
-    public <T extends PageStation> T openFakeLink(String url, Builder<T> builder) {
+    public <T extends CtaPageStation> T openFakeLink(String url, Builder<T> builder) {
         return runOnUiThreadTo(
                         () ->
                                 getActivity()
@@ -190,19 +187,19 @@
     }
 
     /** Move to next tab by swiping the toolbar left. */
-    public <T extends PageStation> T swipeToolbarToNextTab(
-            PageStation.Builder<T> destinationBuilder) {
+    public <T extends CtaPageStation> T swipeToolbarToNextTab(
+            CtaPageStation.Builder<T> destinationBuilder) {
         return swipeToolbar(destinationBuilder, /* directionRight= */ false);
     }
 
     /** Move to previous tab by swiping the toolbar right. */
-    public <T extends PageStation> T swipeToolbarToPreviousTab(
-            PageStation.Builder<T> destinationBuilder) {
+    public <T extends CtaPageStation> T swipeToolbarToPreviousTab(
+            CtaPageStation.Builder<T> destinationBuilder) {
         return swipeToolbar(destinationBuilder, /* directionRight= */ true);
     }
 
-    public <T extends PageStation> T swipeToolbar(
-            PageStation.Builder<T> destinationBuilder, boolean directionRight) {
+    public <T extends CtaPageStation> T swipeToolbar(
+            CtaPageStation.Builder<T> destinationBuilder, boolean directionRight) {
         ToolbarSwipeCoordinates coords =
                 new ToolbarSwipeCoordinates(toolbarElement.get(), directionRight);
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageAppMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageAppMenuFacility.java
index 87edf3bc..48e3b6d7 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageAppMenuFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PageAppMenuFacility.java
@@ -26,7 +26,7 @@
 /**
  * The app menu shown when pressing ("...") in a Tab.
  *
- * <p>Use subclasses to access menu items not shared between all PageStation types:
+ * <p>Use subclasses to access menu items not shared between all {@link CtaPageStation} types:
  *
  * <ul>
  *   <li>{@link RegularNewTabPageAppMenuFacility}
@@ -35,9 +35,9 @@
  *   <li>{@link IncognitoWebPageAppMenuFacility}
  * </ul>
  *
- * @param <HostPageStationT> the type of host {@link PageStation} where this app menu is opened.
+ * @param <HostPageStationT> the type of host {@link CtaPageStation} where this app menu is opened.
  */
-public class PageAppMenuFacility<HostPageStationT extends PageStation>
+public class PageAppMenuFacility<HostPageStationT extends CtaPageStation>
         extends CtaAppMenuFacility<HostPageStationT> {
 
     protected Item mNewTab;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PdfCtaPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PdfCtaPageStation.java
index 1a75fe0..9dd9a733 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PdfCtaPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/PdfCtaPageStation.java
@@ -22,7 +22,7 @@
 import org.chromium.chrome.test.R;
 
 /** The screen that shows a native PDF page within a tabbed activity. */
-public class PdfCtaPageStation extends PageStation {
+public class PdfCtaPageStation extends CtaPageStation {
 
     public final Element<PdfPage> pdfNativePageElement;
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/SwipingToTabFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/SwipingToTabFacility.java
index d833b8b..0d9f11f1 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/SwipingToTabFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/SwipingToTabFacility.java
@@ -9,7 +9,7 @@
 import org.chromium.chrome.test.transit.layouts.LayoutTypeVisibleCondition;
 
 /** Represents the state while swiping the toolbar, moving between two tabs. */
-public class SwipingToTabFacility extends Facility<PageStation> {
+public class SwipingToTabFacility extends Facility<CtaPageStation> {
     private final Runnable mFinishDragTrigger;
 
     public SwipingToTabFacility(Runnable finishDragTrigger) {
@@ -23,8 +23,8 @@
                         mHostStation.getActivityElement(), LayoutType.TOOLBAR_SWIPE));
     }
 
-    /** Finish the swipe to land at a {@link PageStation}. */
-    public <T extends PageStation> T finishSwipe(PageStation.Builder<T> destinationBuilder) {
+    /** Finish the swipe to land at a {@link CtaPageStation}. */
+    public <T extends CtaPageStation> T finishSwipe(CtaPageStation.Builder<T> destinationBuilder) {
         return runTo(mFinishDragTrigger)
                 .arriveAt(
                         destinationBuilder
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java
index d77abaf..3604821 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/TabSwitcherActionMenuFacility.java
@@ -26,8 +26,10 @@
 import org.chromium.chrome.test.transit.tabmodel.TabCountChangedCondition;
 import org.chromium.chrome.test.transit.tabmodel.TabModelChangedCondition;
 
-/** The action menu opened when long pressing the tab switcher button in a {@link PageStation}. */
-public class TabSwitcherActionMenuFacility extends Facility<PageStation> {
+/**
+ * The action menu opened when long pressing the tab switcher button in a {@link CtaPageStation}.
+ */
+public class TabSwitcherActionMenuFacility extends Facility<CtaPageStation> {
     public ViewElement<View> appMenuListElement;
     public ViewElement<View> closeTabMenuItemElement;
     public ViewElement<View> newTabMenuItemElement;
@@ -99,8 +101,8 @@
      *
      * <p>This happens when there are other tabs in the same TabModel.
      */
-    public <T extends PageStation> T selectCloseTabAndDisplayAnotherTab(
-            PageStation.Builder<T> pageStationBuilder) {
+    public <T extends CtaPageStation> T selectCloseTabAndDisplayAnotherTab(
+            CtaPageStation.Builder<T> pageStationBuilder) {
         return selectCloseTabTo()
                 .arriveAt(pageStationBuilder.initFrom(mHostStation).withIsSelectingTabs(1).build());
     }
@@ -111,8 +113,8 @@
      *
      * <p>This happens when the last incognito tab is closed but there are other regular tabs.
      */
-    public <T extends PageStation> T selectCloseTabAndDisplayRegularTab(
-            PageStation.Builder<T> pageStationBuilder) {
+    public <T extends CtaPageStation> T selectCloseTabAndDisplayRegularTab(
+            CtaPageStation.Builder<T> pageStationBuilder) {
         return selectCloseTabTo()
                 .arriveAt(
                         pageStationBuilder.withIncognito(false).initSelectingExistingTab().build());
@@ -143,8 +145,8 @@
     }
 
     /** Switches out of incognito tab model to regular tab model */
-    public <T extends PageStation> T selectSwitchOutOfIncognito(
-            PageStation.Builder<T> destinationBuilder) {
+    public <T extends CtaPageStation> T selectSwitchOutOfIncognito(
+            CtaPageStation.Builder<T> destinationBuilder) {
         assertTrue(mHostStation.isIncognito());
         return switchOutOfIncognitoMenuItemElement
                 .clickTo()
@@ -153,8 +155,8 @@
     }
 
     /** Switches to incognito tab model from regular tab model */
-    public <T extends PageStation> T selectSwitchToIncognito(
-            PageStation.Builder<T> destinationBuilder) {
+    public <T extends CtaPageStation> T selectSwitchToIncognito(
+            CtaPageStation.Builder<T> destinationBuilder) {
         assertFalse(mHostStation.isIncognito());
         return switchToIncognitoMenuItemElement
                 .clickTo()
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/WebPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/WebPageStation.java
index fd181a3..1f08b9a 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/WebPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/page/WebPageStation.java
@@ -26,7 +26,7 @@
 import java.util.concurrent.TimeoutException;
 
 /** The screen that shows a loaded webpage with the omnibox and the toolbar. */
-public class WebPageStation extends PageStation {
+public class WebPageStation extends CtaPageStation {
     public Element<WebContents> webContentsElement;
     public ViewElement<UrlBar> urlBarElement;
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/tabmodel/TabGroupUiFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/tabmodel/TabGroupUiFacility.java
index 519f796..f68da46 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/tabmodel/TabGroupUiFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/tabmodel/TabGroupUiFacility.java
@@ -11,16 +11,18 @@
 import org.chromium.base.test.transit.Facility;
 import org.chromium.base.test.transit.ViewElement;
 import org.chromium.chrome.tab_ui.R;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 
 import java.util.List;
 
 /**
  * Represents the bottom tab strip UI. As TabStrip UI can show on both NTP and web pages.
  *
- * @param <HostStationT> Page that can be a simple {@link PageStation}, or a {@link WebPageStation}.
+ * @param <HostStationT> Page that can be a simple {@link CtaPageStation}, or a {@link
+ *     WebPageStation}.
  */
-public class TabGroupUiFacility<HostStationT extends PageStation> extends Facility<HostStationT> {
+public class TabGroupUiFacility<HostStationT extends CtaPageStation>
+        extends Facility<HostStationT> {
     private final List<Integer> mTabIds;
     public ViewElement<View> viewElement;
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/BlankPopupOnLoadPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/BlankPopupOnLoadPageStation.java
index 2e5baa1..a43e683 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/BlankPopupOnLoadPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/BlankPopupOnLoadPageStation.java
@@ -7,7 +7,7 @@
 import android.util.Pair;
 
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.PopupBlockedMessageFacility;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 
@@ -28,7 +28,8 @@
      */
     public static Pair<BlankPopupOnLoadPageStation, PopupBlockedMessageFacility>
             loadInCurrentTabExpectBlocked(
-                    ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
+                    ChromeTabbedActivityTestRule activityTestRule,
+                    CtaPageStation currentPageStation) {
         String url = activityTestRule.getTestServer().getURL(PATH);
         PopupBlockedMessageFacility<BlankPopupOnLoadPageStation> popupBlockedMessage =
                 new PopupBlockedMessageFacility<>(1);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java
index 719ac58..829eacc 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnClickPageStation.java
@@ -6,7 +6,7 @@
 
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.transit.page.CctPageStation;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.PopupBlockedMessageFacility;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.content_public.browser.test.transit.HtmlElement;
@@ -35,7 +35,7 @@
 
     /** Load popup_on_click.html in current tab. */
     public static PopupOnClickPageStation loadInCurrentTab(
-            ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
+            ChromeTabbedActivityTestRule activityTestRule, CtaPageStation currentPageStation) {
         Builder<PopupOnClickPageStation> builder = new Builder<>(PopupOnClickPageStation::new);
 
         String url = activityTestRule.getTestServer().getURL(PATH);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java
index dcf0f69..15f6239 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/PopupOnLoadPageStation.java
@@ -7,7 +7,7 @@
 import android.util.Pair;
 
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.PopupBlockedMessageFacility;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 
@@ -29,7 +29,8 @@
      */
     public static Pair<PopupOnLoadPageStation, PopupBlockedMessageFacility>
             loadInCurrentTabExpectBlocked(
-                    ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
+                    ChromeTabbedActivityTestRule activityTestRule,
+                    CtaPageStation currentPageStation) {
         // TODO(crbug.com/329307093): Add condition that no new tabs were opened.
         String url = activityTestRule.getTestServer().getURL(PATH);
         PopupOnLoadPageStation newPage =
@@ -49,7 +50,7 @@
      * @return the now active PageStation two.html
      */
     public static WebPageStation loadInCurrentTabExpectPopups(
-            ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
+            ChromeTabbedActivityTestRule activityTestRule, CtaPageStation currentPageStation) {
         // TODO(crbug.com/329307093): Add condition that two new tabs were opened.
         String url = activityTestRule.getTestServer().getURL(PATH);
         return currentPageStation.loadPageProgrammatically(
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
index 21b64a5..ce7fe641 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
@@ -9,7 +9,7 @@
 import org.chromium.base.test.transit.Facility;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.transit.context_menu.LinkContextMenuFacility;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.content_public.browser.test.transit.HtmlElement;
 import org.chromium.content_public.browser.test.transit.HtmlElementSpec;
@@ -31,7 +31,7 @@
 
     /** Load the page, land at the {@link TopFacility} of a {@link TopBottomLinksPageStation}. */
     public static Pair<TopBottomLinksPageStation, TopFacility> loadPage(
-            ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
+            ChromeTabbedActivityTestRule activityTestRule, CtaPageStation currentPageStation) {
         String url = activityTestRule.getTestServer().getURL(PATH);
         TopFacility topFacility = new TopFacility();
         TopBottomLinksPageStation station =
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ui/MessageFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ui/MessageFacility.java
index ed8aa1d..e5e9a99 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ui/MessageFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ui/MessageFacility.java
@@ -23,7 +23,7 @@
 import org.chromium.base.test.transit.TripBuilder;
 import org.chromium.base.test.transit.ViewElement;
 import org.chromium.chrome.test.R;
-import org.chromium.chrome.test.transit.page.PageStation;
+import org.chromium.chrome.test.transit.page.CtaPageStation;
 import org.chromium.components.messages.DismissReason;
 import org.chromium.components.messages.MessageDispatcher;
 import org.chromium.components.messages.MessageDispatcherProvider;
@@ -41,7 +41,7 @@
  *
  * @param <HostStationT> the type of host {@link Station} this is scoped to.
  */
-public class MessageFacility<HostStationT extends PageStation> extends Facility<HostStationT> {
+public class MessageFacility<HostStationT extends CtaPageStation> extends Facility<HostStationT> {
     public ViewElement<View> bannerElement;
     public ViewElement<View> iconElement;
 
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 3ec0699..2f8f1a19 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.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 "chrome/test/chromedriver/chrome/devtools_client_impl.h"
 
 #include <cstring>
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker.cc b/chrome/test/chromedriver/chrome/navigation_tracker.cc
index 2529af8e..106858b 100644
--- a/chrome/test/chromedriver/chrome/navigation_tracker.cc
+++ b/chrome/test/chromedriver/chrome/navigation_tracker.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 "chrome/test/chromedriver/chrome/navigation_tracker.h"
 
 #include <unordered_map>
diff --git a/chrome/test/chromedriver/js/get_element_location.js b/chrome/test/chromedriver/js/get_element_location.js
index 46a94351..e29730f 100644
--- a/chrome/test/chromedriver/js/get_element_location.js
+++ b/chrome/test/chromedriver/js/get_element_location.js
@@ -75,41 +75,6 @@
   var top = Math.max(0, rect.top);
   var bottom = Math.min(window.innerHeight, rect.bottom);
 
-  // Find the view boundary of the element by checking itself and all of its
-  // ancestor's boundary.
-  while (element.parentElement != null &&
-         element.parentElement != document.body &&
-         element.parentElement.getClientRects().length > 0) {
-    var parentStyle = window.getComputedStyle(element.parentElement);
-    var overflow = parentStyle.getPropertyValue("overflow");
-    var overflowX = parentStyle.getPropertyValue("overflow-x");
-    var overflowY = parentStyle.getPropertyValue("overflow-y");
-    var parentRect = getParentRect(element);
-    // Only consider about overflow cases when the parent area overlaps with
-    // the element's area.
-    if (parentRect.right > left && parentRect.bottom > top &&
-        right > parentRect.left && bottom > parentRect.top) {
-      if (overflow == "auto" || overflow == "scroll" || overflow == "hidden") {
-        left = Math.max(left, parentRect.left);
-        right = Math.min(right, parentRect.right);
-        top = Math.max(top, parentRect.top);
-        bottom = Math.min(bottom, parentRect.bottom);
-      } else {
-        if (overflowX == "auto" || overflowX == "scroll" ||
-            overflowX == "hidden") {
-          left = Math.max(left, parentRect.left);
-          right = Math.min(right, parentRect.right);
-        }
-        if (overflowY == "auto" || overflowY == "scroll" ||
-            overflowY == "hidden") {
-          top = Math.max(top, parentRect.top);
-          bottom = Math.min(bottom, parentRect.bottom);
-        }
-      }
-    }
-    element = element.parentElement;
-  }
-
   var x = 0.5 * (left + right);
   var y = 0.5 * (top + bottom);
   return [x, y, left, top];
diff --git a/chrome/test/chromedriver/net/adb_client_socket.cc b/chrome/test/chromedriver/net/adb_client_socket.cc
index 54ea7e4..64845a160 100644
--- a/chrome/test/chromedriver/net/adb_client_socket.cc
+++ b/chrome/test/chromedriver/net/adb_client_socket.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/test/chromedriver/net/adb_client_socket.h"
 
 #include <stddef.h>
@@ -57,8 +52,8 @@
   CHECK_LE(length, 0xffffu);
   std::string result;
   result.reserve(4);
-  base::AppendHexEncodedByte(reinterpret_cast<const uint8_t*>(&length)[1],
-                             result);
+  base::AppendHexEncodedByte(
+      UNSAFE_TODO(reinterpret_cast<const uint8_t*>(&length)[1]), result);
   base::AppendHexEncodedByte(reinterpret_cast<const uint8_t*>(&length)[0],
                              result);
   return result + message;
@@ -389,7 +384,8 @@
     size_t offset = current_offset_;
     size_t length = std::min(content_.length() - offset, kAdbDataChunkSize);
     current_offset_ += length;
-    SendPayload(kDataCommand, length, content_.c_str() + offset, length,
+    SendPayload(kDataCommand, length, UNSAFE_TODO(content_.c_str() + offset),
+                length,
                 base::BindOnce(&AdbSendFileSocket::SendContent,
                                base::Unretained(this)));
   }
diff --git a/chrome/test/chromedriver/net/adb_client_socket_unittest.cc b/chrome/test/chromedriver/net/adb_client_socket_unittest.cc
index e82c952..1a898ca 100644
--- a/chrome/test/chromedriver/net/adb_client_socket_unittest.cc
+++ b/chrome/test/chromedriver/net/adb_client_socket_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 "chrome/test/chromedriver/net/adb_client_socket.h"
 
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_span.h"
@@ -54,11 +50,13 @@
     }
     int chunk_length = return_values_array.front().length();
     if (chunk_length > buf_len) {
-      strncpy(buf->data(), return_values_array.front().data(), buf_len);
+      UNSAFE_TODO(
+          strncpy(buf->data(), return_values_array.front().data(), buf_len));
       return_values_array.front() = return_values_array.front().substr(buf_len);
       return buf_len;
     }
-    strncpy(buf->data(), return_values_array.front().data(), chunk_length);
+    UNSAFE_TODO(
+        strncpy(buf->data(), return_values_array.front().data(), chunk_length));
     return_values_array = return_values_array.subspan<1>();
     if (chunk_length == 0) {
       return net::ERR_IO_PENDING;
@@ -110,7 +108,7 @@
     scoped_refptr<net::GrowableIOBuffer> buffer =
         base::MakeRefCounted<net::GrowableIOBuffer>();
     buffer->SetCapacity(100);
-    strcpy(buffer->data(), data_on_buffer);
+    UNSAFE_TODO(strcpy(buffer->data(), data_on_buffer));
     buffer->set_offset(strlen(data_on_buffer));
 
     adb_socket.ReadUntilEOF(parse_callback.Get(), response_callback.Get(),
@@ -180,7 +178,7 @@
     int initial_capacity = 100;
     buffer->SetCapacity(initial_capacity);
     if (result > 0) {
-      strncpy(buffer->data(), buffer_data, result);
+      UNSAFE_TODO(strncpy(buffer->data(), buffer_data, result));
     }
     AdbClientSocket::ReadStatusOutput(response_callback.Get(), buffer, result);
   }
diff --git a/chrome/test/chromedriver/net/pipe_connection_posix.cc b/chrome/test/chromedriver/net/pipe_connection_posix.cc
index fe5988c3..55cafd8 100644
--- a/chrome/test/chromedriver/net/pipe_connection_posix.cc
+++ b/chrome/test/chromedriver/net/pipe_connection_posix.cc
@@ -4,17 +4,13 @@
 
 #include "chrome/test/chromedriver/net/pipe_connection_posix.h"
 
-#include "base/functional/callback_forward.h"
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <list>
 #include <memory>
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
+#include "base/functional/callback_forward.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
@@ -291,7 +287,7 @@
 
     // enqueue with the trailing zero character
     queued_.insert(queued_.end(), message.c_str(),
-                   message.c_str() + message.size() + 1);
+                   UNSAFE_TODO(message.c_str() + message.size() + 1));
     if (!write_buffer_->BytesRemaining()) {
       const size_t queued_size = queued_.size();
       write_buffer_ = base::MakeRefCounted<net::DrainableIOBuffer>(
diff --git a/chrome/test/chromedriver/net/pipe_reader_posix_unittest.cc b/chrome/test/chromedriver/net/pipe_reader_posix_unittest.cc
index 5fdb5cf..ea17e4b0 100644
--- a/chrome/test/chromedriver/net/pipe_reader_posix_unittest.cc
+++ b/chrome/test/chromedriver/net/pipe_reader_posix_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <cmath>
 #include <string>
 
@@ -86,7 +81,7 @@
         break;
       }
       received_message.insert(received_message.end(), buffer->data(),
-                              buffer->data() + rv);
+                              UNSAFE_TODO(buffer->data() + rv));
     }
     return std::make_pair(std::move(received_message), rv);
   }
diff --git a/chrome/test/chromedriver/net/pipe_writer_posix_unittest.cc b/chrome/test/chromedriver/net/pipe_writer_posix_unittest.cc
index 1312ffdb..9c32400 100644
--- a/chrome/test/chromedriver/net/pipe_writer_posix_unittest.cc
+++ b/chrome/test/chromedriver/net/pipe_writer_posix_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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <cmath>
 #include <string>
 
@@ -43,12 +38,13 @@
       base::MakeRefCounted<net::IOBufferWithSize>(4096);
   int rv = 0;
   while (true) {
-    rv = read_pipe.ReadAtCurrentPos(buffer->data(), buffer->size());
+    rv =
+        UNSAFE_TODO(read_pipe.ReadAtCurrentPos(buffer->data(), buffer->size()));
     if (rv <= 0) {
       break;
     }
     received_message.insert(received_message.end(), buffer->data(),
-                            buffer->data() + rv);
+                            UNSAFE_TODO(buffer->data() + rv));
   }
   return std::make_pair(std::move(received_message), rv);
 }
diff --git a/chrome/test/chromedriver/server/http_server.cc b/chrome/test/chromedriver/server/http_server.cc
index 3819b161..153c3bff 100644
--- a/chrome/test/chromedriver/server/http_server.cc
+++ b/chrome/test/chromedriver/server/http_server.cc
@@ -2,13 +2,9 @@
 // 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 "chrome/test/chromedriver/server/http_server.h"
 
+#include "base/compiler_specific.h"
 #include "base/strings/string_util.h"
 #include "base/task/single_thread_task_runner.h"
 #include "net/base/ip_endpoint.h"
@@ -52,7 +48,7 @@
 
 void GetCanonicalHostName(std::vector<std::string>* canonical_host_names) {
   struct addrinfo hints, *info = nullptr, *p;
-  memset(&hints, 0, sizeof(hints));
+  UNSAFE_TODO(memset(&hints, 0, sizeof(hints)));
   hints.ai_family = AF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags = AI_CANONNAME;
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 47e761e..2112b3d 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -5504,6 +5504,47 @@
     self._driver.MouseDoubleClick()
     self.assertEqual(1, len(self._driver.FindElements('tag name', 'br')))
 
+  def testMouseActionOriginMatchesMoveToWithOverflowHiddenParent(self):
+    """Regression test for crbug.com/42322257
+    """
+    # Setting overflow: hidden on the parent element is required for this issue
+    # to manifest.
+    self._http_server.SetDataForPath('/page.html', bytes("""
+      <html><body>
+        <div style='position: absolute; top: 74px;
+          overflow: hidden; height: 1637px; width: 175px;'>
+          <div id='test' style='position: relative; top: -30px;
+            height: 1471px'></div>
+          </div>
+      <script>
+        clicks = [];
+        document.getElementById('test').addEventListener(
+          'click', function (event) {
+            clicks.push([event.clientX, event.clientY]);
+          });
+      </script>
+      </body></html>""", 'utf-8'))
+    self._driver.Load(self.GetHttpUrlForFile('/page.html'))
+    element = self._driver.FindElement('css selector', '#test')
+    element.Click()
+    self._driver.MouseMoveTo(element)
+    self._driver.MouseClick()
+    self._driver.MouseMoveTo(element)
+    self._driver.MouseDoubleClick()
+    actions = ({'actions': [{
+      'type': 'pointer',
+      'actions': [{'type': 'pointerMove', 'x': 0, 'y': 0, 'origin': element},
+                  {'type': 'pointerDown', 'button': 0},
+                  {'type': 'pointerUp', 'button': 0}],
+      'id': 'pointer1'}]})
+    self._driver.PerformActions(actions)
+    clicks = self._driver.ExecuteScript("return clicks;")
+    self.assertEqual(5, len(clicks))
+    for index in range (1, len(clicks)):
+      self.assertIsNotNone(clicks[0])
+      self.assertEqual(clicks[0][0], clicks[index][0])
+      self.assertEqual(clicks[0][1], clicks[index][1])
+
   def testMouseMoveTo(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
     div = self._driver.ExecuteScript(
diff --git a/chrome/test/chromedriver/util.cc b/chrome/test/chromedriver/util.cc
index 22f31ab..8b362f5 100644
--- a/chrome/test/chromedriver/util.cc
+++ b/chrome/test/chromedriver/util.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/test/chromedriver/util.h"
 
 #include <stddef.h>
@@ -16,6 +11,7 @@
 #include <string_view>
 
 #include "base/base64.h"
+#include "base/compiler_specific.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -139,7 +135,7 @@
       return;
     size_t next = buffer_.length();
     buffer_.resize(next + size);
-    memcpy(&buffer_[next], bytes, size);
+    UNSAFE_TODO(memcpy(&buffer_[next], bytes, size));
   }
 
   const std::string& buffer() const { return buffer_; }
@@ -174,7 +170,7 @@
   bool ReadBytes(void* bytes, int size) {
     if (iter_ + size > size_)
       return false;
-    memcpy(bytes, &data_[iter_], size);
+    UNSAFE_TODO(memcpy(bytes, &data_[iter_], size));
     iter_ += size;
     return true;
   }
diff --git a/chrome/test/data/web_apps/sample_web_app.json b/chrome/test/data/web_apps/sample_web_app.json
index 2c62f49..4276032 100644
--- a/chrome/test/data/web_apps/sample_web_app.json
+++ b/chrome/test/data/web_apps/sample_web_app.json
@@ -1,13 +1,13 @@
 {
    "!app_id": "ejhkbejlajgoplgondfmjmplbdjaofok",
    "!name": "Name1234",
-   "additional_search_terms": [ "Foo_1234_0", "Foo_1234_1", "Foo_1234_2", "Foo_1234_3" ],
-   "allowed_launch_protocols": [ "web+test_1234_0", "web+test_1234_1", "web+test_1234_2", "web+test_1234_3" ],
+   "additional_search_terms": [ "Foo_1234_0", "Foo_1234_1", "Foo_1234_2" ],
+   "allowed_launch_protocols": [ "web+test_1234_0", "web+test_1234_1", "web+test_1234_2", "web+test_1234_3", "web+test_1234_4", "web+test_1234_5", "web+test_1234_6" ],
    "always_show_toolbar_in_fullscreen": true,
    "app_service_icon_url": "chrome://app-icon/ejhkbejlajgoplgondfmjmplbdjaofok/32",
-   "app_size_in_bytes": "2008198819",
+   "app_size_in_bytes": "314765861",
    "background_color": "rgba(151,34,83,1)",
-   "capture_links": "kExistingClientNavigate",
+   "capture_links": "kNone",
    "current_os_integration_states": {
       "file_handling": {
          "file_handlers": [ {
@@ -23,9 +23,6 @@
          "protocols": [ {
             "protocol": "web+test0",
             "url": "https://example.com/scope1234/start12340"
-         }, {
-            "protocol": "web+test1",
-            "url": "https://example.com/scope1234/start12341"
          } ]
       },
       "run_on_os_login": {
@@ -35,23 +32,23 @@
          "description": "Description1234",
          "icon_data_any": [ {
             "icon_size": 32,
-            "timestamp": "2207579808"
+            "timestamp": "1262862595"
          } ],
          "title": "Name1234"
       },
       "shortcut_menus": {
          "shortcut_menu_info": [ {
             "icon_data_any": [ {
-               "icon_size": 48,
-               "timestamp": "1562452713"
+               "icon_size": 16,
+               "timestamp": "1430602893"
             } ],
             "icon_data_maskable": [ {
                "icon_size": 16,
-               "timestamp": "580345477"
+               "timestamp": "301524967"
             } ],
             "icon_data_monochrome": [ {
-               "icon_size": 32,
-               "timestamp": "85043124"
+               "icon_size": 16,
+               "timestamp": "1600328844"
             } ],
             "shortcut_launch_url": "https://example.com/scope1234/0",
             "shortcut_name": "shortcut_name0"
@@ -64,27 +61,27 @@
    },
    "dark_mode_background_color": "rgba(61,127,69,1)",
    "dark_mode_theme_color": "rgba(77,188,194,1)",
-   "data_size_in_bytes": "1919202154",
+   "data_size_in_bytes": "807061987",
    "description": "Description1234",
-   "disallowed_launch_protocols": [ "web+disallowed_1234_0", "web+disallowed_1234_1", "web+disallowed_1234_2", "web+disallowed_1234_3" ],
+   "disallowed_launch_protocols": [ "web+disallowed_1234_0" ],
    "display_mode": "minimal-ui",
    "display_override": [ "standalone" ],
    "diy_app_icons_masked_on_mac": true,
    "downloaded_icon_sizes": {
-      "ANY": [ 256 ],
-      "MASKABLE": [ 512 ],
-      "MONOCHROME": [ 256 ]
+      "ANY": [ 512 ],
+      "MASKABLE": [ 96 ],
+      "MONOCHROME": [ 512 ]
    },
    "file_handler_approval_state": "kRequiresPrompt",
    "file_handlers": [ {
       "accept": [ {
-         "file_extensions": [ ".9866883820a", ".9866883820b" ],
-         "mime_type": "application/9866883820+foo"
+         "file_extensions": [ ".20773535220a", ".20773535220b" ],
+         "mime_type": "application/20773535220+foo"
       }, {
-         "file_extensions": [ ".9866883820a", ".9866883820b" ],
-         "mime_type": "application/9866883820+bar"
+         "file_extensions": [ ".20773535220a", ".20773535220b" ],
+         "mime_type": "application/20773535220+bar"
       } ],
-      "action": "https://example.com/open-9866883820",
+      "action": "https://example.com/open-20773535220",
       "downloaded_icons": [ {
          "purpose": "kAny",
          "square_size_px": 16,
@@ -95,16 +92,16 @@
          "url": "https://example.com/image2.png"
       } ],
       "launch_type": "kSingleClient",
-      "name": "9866883820 file"
+      "name": "20773535220 file"
    }, {
       "accept": [ {
-         "file_extensions": [ ".9866883821a", ".9866883821b" ],
-         "mime_type": "application/9866883821+foo"
+         "file_extensions": [ ".20773535221a", ".20773535221b" ],
+         "mime_type": "application/20773535221+foo"
       }, {
-         "file_extensions": [ ".9866883821a", ".9866883821b" ],
-         "mime_type": "application/9866883821+bar"
+         "file_extensions": [ ".20773535221a", ".20773535221b" ],
+         "mime_type": "application/20773535221+bar"
       } ],
-      "action": "https://example.com/open-9866883821",
+      "action": "https://example.com/open-20773535221",
       "downloaded_icons": [ {
          "purpose": "kAny",
          "square_size_px": 16,
@@ -115,16 +112,16 @@
          "url": "https://example.com/image2.png"
       } ],
       "launch_type": "kSingleClient",
-      "name": "9866883821 file"
+      "name": "20773535221 file"
    }, {
       "accept": [ {
-         "file_extensions": [ ".9866883822a", ".9866883822b" ],
-         "mime_type": "application/9866883822+foo"
+         "file_extensions": [ ".20773535222a", ".20773535222b" ],
+         "mime_type": "application/20773535222+foo"
       }, {
-         "file_extensions": [ ".9866883822a", ".9866883822b" ],
-         "mime_type": "application/9866883822+bar"
+         "file_extensions": [ ".20773535222a", ".20773535222b" ],
+         "mime_type": "application/20773535222+bar"
       } ],
-      "action": "https://example.com/open-9866883822",
+      "action": "https://example.com/open-20773535222",
       "downloaded_icons": [ {
          "purpose": "kAny",
          "square_size_px": 16,
@@ -135,16 +132,16 @@
          "url": "https://example.com/image2.png"
       } ],
       "launch_type": "kSingleClient",
-      "name": "9866883822 file"
+      "name": "20773535222 file"
    }, {
       "accept": [ {
-         "file_extensions": [ ".9866883823a", ".9866883823b" ],
-         "mime_type": "application/9866883823+foo"
+         "file_extensions": [ ".20773535223a", ".20773535223b" ],
+         "mime_type": "application/20773535223+foo"
       }, {
-         "file_extensions": [ ".9866883823a", ".9866883823b" ],
-         "mime_type": "application/9866883823+bar"
+         "file_extensions": [ ".20773535223a", ".20773535223b" ],
+         "mime_type": "application/20773535223+bar"
       } ],
-      "action": "https://example.com/open-9866883823",
+      "action": "https://example.com/open-20773535223",
       "downloaded_icons": [ {
          "purpose": "kAny",
          "square_size_px": 16,
@@ -155,16 +152,16 @@
          "url": "https://example.com/image2.png"
       } ],
       "launch_type": "kSingleClient",
-      "name": "9866883823 file"
+      "name": "20773535223 file"
    }, {
       "accept": [ {
-         "file_extensions": [ ".9866883824a", ".9866883824b" ],
-         "mime_type": "application/9866883824+foo"
+         "file_extensions": [ ".20773535224a", ".20773535224b" ],
+         "mime_type": "application/20773535224+foo"
       }, {
-         "file_extensions": [ ".9866883824a", ".9866883824b" ],
-         "mime_type": "application/9866883824+bar"
+         "file_extensions": [ ".20773535224a", ".20773535224b" ],
+         "mime_type": "application/20773535224+bar"
       } ],
-      "action": "https://example.com/open-9866883824",
+      "action": "https://example.com/open-20773535224",
       "downloaded_icons": [ {
          "purpose": "kAny",
          "square_size_px": 16,
@@ -175,14 +172,14 @@
          "url": "https://example.com/image2.png"
       } ],
       "launch_type": "kSingleClient",
-      "name": "9866883824 file"
+      "name": "20773535224 file"
    } ],
    "first_install_time": "1970-01-02 14:58:07.045000 UTC",
    "generated_icon_fix": {
-      "attempt_count": "40",
-      "last_attempt_time": "1180082344",
+      "attempt_count": "81",
+      "last_attempt_time": "2229210051",
       "source": "GENERATED_ICON_FIX_SOURCE_RETROACTIVE",
-      "window_start_time": "2781833041"
+      "window_start_time": "1587293902"
    },
    "install_state": "1",
    "is_diy_app": true,
@@ -192,14 +189,14 @@
    "isolation_data": null,
    "last_badging_time": "1970-01-28 05:07:28.623000 UTC",
    "last_launch_time": "1970-01-27 09:52:51.713000 UTC",
-   "latest_install_source": "menu custom tab",
-   "latest_install_time": "1970-01-26 19:13:30.051000 UTC",
+   "latest_install_source": "api custom tab",
+   "latest_install_time": "1970-02-16 02:04:31.062000 UTC",
    "launch_handler": {
       "client_mode": "kAuto",
       "client_mode_valid_and_specified": false
    },
    "launch_query_params": "144210110",
-   "lock_screen_start_url": "https://example.com/scope1234/lock_screen_start_url4113628103",
+   "lock_screen_start_url": "https://example.com/scope1234/lock_screen_start_url3384912140",
    "management_type_to_external_configuration_map": {
       "ApsDefault": {
          "additional_policy_ids": [ "policy_id_1_1234", "policy_id_2_1234" ],
@@ -246,122 +243,178 @@
       "purpose": "kMonochrome",
       "square_size_px": 96,
       "url": "https://example.com/icons322714900"
+   }, {
+      "purpose": "kMaskable",
+      "square_size_px": 512,
+      "url": "https://example.com/icons2945661221"
    } ],
    "manifest_id": "https://example.com/manifest_id_1234?query=test",
-   "manifest_update_time": "1970-02-14 02:35:26.940000 UTC",
+   "manifest_update_time": "1970-02-07 00:45:27.577000 UTC",
    "manifest_url": "https://example.com/manifest1234.json",
-   "note_taking_new_note_url": "https://example.com/scope1234/new_note944292860",
-   "parent_app_id": "16836321",
+   "note_taking_new_note_url": "https://example.com/scope1234/new_note1308772041",
+   "parent_app_id": "3081384793",
    "pending_update_info": {
       "manifest_icons": [ {
+         "purpose": "ANY",
+         "size_in_px": 48,
+         "url": "https://example.com/icons548968974"
+      }, {
          "purpose": "MASKABLE",
-         "size_in_px": 32,
-         "url": "https://example.com/icon1440847613"
+         "size_in_px": 128,
+         "url": "https://example.com/icons1977240764"
       }, {
          "purpose": "MONOCHROME",
-         "size_in_px": 192,
-         "url": "https://example.com/icon53340626"
+         "size_in_px": 512,
+         "url": "https://example.com/icons3978324406"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 128,
+         "url": "https://example.com/icons428675460"
+      }, {
+         "purpose": "MONOCHROME",
+         "size_in_px": 256,
+         "url": "https://example.com/icons2122629625"
+      }, {
+         "purpose": "MONOCHROME",
+         "size_in_px": 1024,
+         "url": "https://example.com/icons2161309441"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 1024,
+         "url": "https://example.com/icons145131398"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 96,
+         "url": "https://example.com/icons2464720889"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 96,
+         "url": "https://example.com/icons2572177745"
+      }, {
+         "purpose": "ANY",
+         "size_in_px": 128,
+         "url": "https://example.com/icons3502924369"
       } ],
       "name": "Name1234",
-      "short_name": "random_short_name_1234"
+      "trusted_icons": [ {
+         "purpose": "ANY",
+         "size_in_px": 48,
+         "url": "https://example.com/icons548968974"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 128,
+         "url": "https://example.com/icons1977240764"
+      }, {
+         "purpose": "MONOCHROME",
+         "size_in_px": 512,
+         "url": "https://example.com/icons3978324406"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 128,
+         "url": "https://example.com/icons428675460"
+      }, {
+         "purpose": "MONOCHROME",
+         "size_in_px": 256,
+         "url": "https://example.com/icons2122629625"
+      }, {
+         "purpose": "MONOCHROME",
+         "size_in_px": 1024,
+         "url": "https://example.com/icons2161309441"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 1024,
+         "url": "https://example.com/icons145131398"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 96,
+         "url": "https://example.com/icons2464720889"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": 96,
+         "url": "https://example.com/icons2572177745"
+      }, {
+         "purpose": "ANY",
+         "size_in_px": 128,
+         "url": "https://example.com/icons3502924369"
+      } ]
    },
    "permissions_policy": [ {
-      "allowed_origins": [ "https://app-3147658610.com" ],
+      "allowed_origins": [ "https://app-33043395560.com" ],
       "feature": "accelerometer",
       "matches_all_origins": true,
       "matches_opaque_src": true
    }, {
-      "allowed_origins": [ "https://app-3147658610.com", "https://app-3147658611.com" ],
+      "allowed_origins": [ "https://app-33043395560.com" ],
       "feature": "accelerometer",
       "matches_all_origins": true,
       "matches_opaque_src": true
    } ],
    "protocol_handlers": [ {
-      "protocol": "web+test20773535220",
-      "url": "https://example.com/20773535220"
+      "protocol": "web+test9442928600",
+      "url": "https://example.com/9442928600"
    }, {
-      "protocol": "web+test20773535221",
-      "url": "https://example.com/20773535221"
+      "protocol": "web+test9442928601",
+      "url": "https://example.com/9442928601"
    }, {
-      "protocol": "web+test20773535222",
-      "url": "https://example.com/20773535222"
+      "protocol": "web+test9442928602",
+      "url": "https://example.com/9442928602"
    }, {
-      "protocol": "web+test20773535223",
-      "url": "https://example.com/20773535223"
+      "protocol": "web+test9442928603",
+      "url": "https://example.com/9442928603"
    }, {
-      "protocol": "web+test20773535224",
-      "url": "https://example.com/20773535224"
+      "protocol": "web+test9442928604",
+      "url": "https://example.com/9442928604"
    } ],
    "related_applications": [ {
-      "id": "id4",
-      "platform": "chromeos_play",
-      "url": "https://example.com/4"
-   }, {
-      "id": "id3",
-      "platform": "play",
-      "url": "https://example.com/3"
-   }, {
       "id": "id2",
-      "platform": "amazon",
+      "platform": "play",
       "url": "https://example.com/2"
    }, {
       "id": "id1",
-      "platform": "webapp",
+      "platform": "play",
       "url": "https://example.com/1"
    }, {
       "id": "id0",
-      "platform": "chromeos_play",
+      "platform": "play",
       "url": "https://example.com/0"
    } ],
    "run_on_os_login_mode": "windowed",
    "scope": "https://example.com/scope1234/",
    "scope_extensions": [ {
       "has_origin_wildcard": true,
-      "origin": "https://app-32091131550.com",
-      "scope": "https://app-32091131550.com/"
+      "origin": "https://app-37137172470.com",
+      "scope": "https://app-37137172470.com/"
    }, {
       "has_origin_wildcard": true,
-      "origin": "https://app-32091131551.com",
-      "scope": "https://app-32091131551.com/"
+      "origin": "https://app-37137172471.com",
+      "scope": "https://app-37137172471.com/"
    }, {
       "has_origin_wildcard": true,
-      "origin": "https://app-32091131552.com",
-      "scope": "https://app-32091131552.com/"
+      "origin": "https://app-37137172472.com",
+      "scope": "https://app-37137172472.com/"
    } ],
    "scope_extensions_validated": [ {
       "has_origin_wildcard": true,
-      "origin": "https://app-32091131550.com",
-      "scope": "https://app-32091131550.com/"
+      "origin": "https://app-37137172470.com",
+      "scope": "https://app-37137172470.com/"
    }, {
       "has_origin_wildcard": true,
-      "origin": "https://app-32091131551.com",
-      "scope": "https://app-32091131551.com/"
+      "origin": "https://app-37137172471.com",
+      "scope": "https://app-37137172471.com/"
    }, {
       "has_origin_wildcard": true,
-      "origin": "https://app-32091131552.com",
-      "scope": "https://app-32091131552.com/"
+      "origin": "https://app-37137172472.com",
+      "scope": "https://app-37137172472.com/"
    } ],
    "share_target": {
-      "action": "https://example.com/path/target/1739605659",
+      "action": "https://example.com/path/target/3209113155",
       "enctype": "application/x-www-form-urlencoded",
       "method": "GET",
       "params": {
-         "files": [ {
-            "accept": [ ".extension0", "type/subtype0" ],
-            "name": "files0"
-         }, {
-            "accept": [ ".extension1", "type/subtype1" ],
-            "name": "files1"
-         }, {
-            "accept": [ ".extension2", "type/subtype2" ],
-            "name": "files2"
-         }, {
-            "accept": [ ".extension3", "type/subtype3" ],
-            "name": "files3"
-         } ],
-         "text": "text1739605659",
+         "files": [  ],
+         "text": "text3209113155",
          "title": "",
-         "url": "url1739605659"
+         "url": "url3209113155"
       }
    },
    "shortcuts_menu_item_infos": [ {
@@ -373,69 +426,61 @@
       "icons": {
          "ANY": [  ],
          "MASKABLE": [ {
-            "square_size_px": 34,
-            "url": "https://example.com/shortcuts/icon121095827613"
-         }, {
-            "square_size_px": 18,
-            "url": "https://example.com/shortcuts/icon121095827611"
-         } ],
-         "MONOCHROME": [ {
-            "square_size_px": 49,
-            "url": "https://example.com/shortcuts/icon121095827614"
-         }, {
-            "square_size_px": 22,
-            "url": "https://example.com/shortcuts/icon121095827612"
+            "square_size_px": 15,
+            "url": "https://example.com/shortcuts/icon25911748411"
          }, {
             "square_size_px": 1,
-            "url": "https://example.com/shortcuts/icon121095827610"
+            "url": "https://example.com/shortcuts/icon25911748410"
+         } ],
+         "MONOCHROME": [ {
+            "square_size_px": 25,
+            "url": "https://example.com/shortcuts/icon25911748412"
          } ]
       },
-      "name": "shortcut12109582761",
-      "url": "https://example.com/scope1234/shortcut12109582761"
+      "name": "shortcut2591174841",
+      "url": "https://example.com/scope1234/shortcut2591174841"
    }, {
       "downloaded_icons_sizes": {
-         "ANY": [ 77 ],
-         "MASKABLE": [ 154 ],
-         "MONOCHROME": [ 90 ]
+         "ANY": [ 147 ],
+         "MASKABLE": [ 58 ],
+         "MONOCHROME": [ 160 ]
       },
       "icons": {
          "ANY": [  ],
          "MASKABLE": [ {
-            "square_size_px": 45,
-            "url": "https://example.com/shortcuts/icon121095827604"
-         }, {
-            "square_size_px": 29,
-            "url": "https://example.com/shortcuts/icon121095827602"
-         }, {
-            "square_size_px": 13,
-            "url": "https://example.com/shortcuts/icon121095827601"
+            "square_size_px": 11,
+            "url": "https://example.com/shortcuts/icon25911748401"
          }, {
             "square_size_px": 1,
-            "url": "https://example.com/shortcuts/icon121095827600"
+            "url": "https://example.com/shortcuts/icon25911748400"
          } ],
          "MONOCHROME": [ {
-            "square_size_px": 38,
-            "url": "https://example.com/shortcuts/icon121095827603"
+            "square_size_px": 21,
+            "url": "https://example.com/shortcuts/icon25911748402"
          } ]
       },
-      "name": "shortcut12109582760",
-      "url": "https://example.com/scope1234/shortcut12109582760"
+      "name": "shortcut2591174840",
+      "url": "https://example.com/scope1234/shortcut2591174840"
    } ],
    "sources": [ "IwaShimlessRma", "Kiosk", "Policy", "IwaPolicy", "OEM", "SubApp", "WebAppStore", "OneDriveIntegration", "Sync", "UserInstalled", "IwaUserInstalled", "ApsDefault", "Default" ],
    "start_url": "https://example.com/scope1234/start1234",
-   "supported_links_offer_dismiss_count": 1242854796,
-   "supported_links_offer_ignore_count": -1560439457,
+   "supported_links_offer_dismiss_count": 1180082344,
+   "supported_links_offer_ignore_count": -1513134255,
    "sync_proto": {
       "icon_infos": [ {
          "purpose": "MONOCHROME",
          "size_in_px": "96",
          "url": "https://example.com/icons322714900"
+      }, {
+         "purpose": "MASKABLE",
+         "size_in_px": "512",
+         "url": "https://example.com/icons2945661221"
       } ],
       "name": "SyncName1234",
       "relative_manifest_id": "manifest_id_1234?query=test",
       "scope": "https://example.com/scope1234/",
       "start_url": "https://example.com/scope1234/start1234",
-      "theme_color": "4288675947",
+      "theme_color": "4290180684",
       "user_display_mode_cros": "STANDALONE",
       "user_display_mode_default": "TABBED",
       "user_launch_ordinal": "n",
@@ -445,54 +490,79 @@
       "home_tab": {
          "icons": [ {
             "purpose": [ "Maskable", "Monochrome" ],
-            "sizes": [ "150x10", "170x37" ],
-            "src": "https://example.com/image3.svg",
+            "sizes": [ "60x38", "154x178" ],
+            "src": "https://example.com/image4.svg",
             "type": "image/svg+xml"
          }, {
+            "purpose": [ "Monochrome", "Maskable" ],
+            "sizes": [ "74x228", "165x43" ],
+            "src": "https://example.com/image3.webp",
+            "type": "image/webp"
+         }, {
             "purpose": [ "Monochrome", "Maskable", "Any" ],
-            "sizes": [ "429x27", "72x266", "141x186" ],
+            "sizes": [ "266x282", "186x97" ],
             "src": "https://example.com/image2.svg",
             "type": "image/svg+xml"
          }, {
             "purpose": [ "Maskable", "Monochrome" ],
-            "sizes": [ "44x148", "133x87" ],
-            "src": "https://example.com/image1.webp",
-            "type": "image/webp"
+            "sizes": [ "148x266", "87x39" ],
+            "src": "https://example.com/image1.svg",
+            "type": "image/svg+xml"
          }, {
             "purpose": [ "Maskable", "Monochrome" ],
-            "sizes": [ "64x58", "35x76" ],
-            "src": "https://example.com/image0.webp",
-            "type": "image/webp"
+            "sizes": [ "58x70", "76x106" ],
+            "src": "https://example.com/image0.svg",
+            "type": "image/svg+xml"
          } ],
          "scope_patterns": [ {
-            "pathname": "{prefix2:name2\\suffix2}{prefix1:name1\\suffix1}?{prefix0:name0(.*)suffix0}+"
+            "pathname": "{prefix2:name2(.*)suffix2}+{prefix1:name1\\suffix1}{prefix0:name0(.*)suffix0}?"
          }, {
-            "pathname": "{prefix2:name2\\suffix2}?{prefix1:name1(.*)suffix1}?{prefix0:name0(.*)suffix0}+"
+            "pathname": "{prefix2:name2\\suffix2}+{prefix1:name1(.*)suffix1}{prefix0:name0(.*)suffix0}"
          }, {
-            "pathname": "{prefix4:name4(.*)suffix4}+{prefix3:name3(.*)suffix3}{prefix2:name2(.*)suffix2}+{prefix1:name1(.*)suffix1}{prefix0:name0(.*)suffix0}?"
+            "pathname": "{prefix2:name2\\suffix2}?{prefix1:name1\\suffix1}+{prefix0:name0(.*)suffix0}+"
          } ]
       },
       "new_tab_button": {
-         "url": "https://example.com/scope1234/new_tab_button_url1896327144"
+         "url": "https://example.com/scope1234/new_tab_button_url3074646863"
       }
    },
    "theme_color": "rgba(220,247,174,1)",
    "trusted_icons": [ {
-      "purpose": "kMonochrome",
-      "square_size_px": 256,
-      "url": "https://example.com/icons2122629625"
+      "purpose": "kMaskable",
+      "square_size_px": 128,
+      "url": "https://example.com/icons3330134367"
    }, {
       "purpose": "kMonochrome",
-      "square_size_px": 1024,
-      "url": "https://example.com/icons2161309441"
+      "square_size_px": 512,
+      "url": "https://example.com/icons716143606"
+   }, {
+      "purpose": "kMaskable",
+      "square_size_px": 128,
+      "url": "https://example.com/icons2588856730"
+   }, {
+      "purpose": "kAny",
+      "square_size_px": 512,
+      "url": "https://example.com/icons4285246002"
+   }, {
+      "purpose": "kMonochrome",
+      "square_size_px": 64,
+      "url": "https://example.com/icons10760248"
+   }, {
+      "purpose": "kMaskable",
+      "square_size_px": 48,
+      "url": "https://example.com/icons1601631484"
+   }, {
+      "purpose": "kMonochrome",
+      "square_size_px": 128,
+      "url": "https://example.com/icons2667443007"
+   }, {
+      "purpose": "kMaskable",
+      "square_size_px": 48,
+      "url": "https://example.com/icons4170548515"
    }, {
       "purpose": "kMaskable",
       "square_size_px": 1024,
-      "url": "https://example.com/icons145131398"
-   }, {
-      "purpose": "kMaskable",
-      "square_size_px": 96,
-      "url": "https://example.com/icons2464720889"
+      "url": "https://example.com/icons443139040"
    } ],
    "user_link_capturing_preference": "1",
    "was_shortcut_app": true,
diff --git a/chrome/test/data/webui/glic/api_test.ts b/chrome/test/data/webui/glic/api_test.ts
index 485ab3341..82baed3 100644
--- a/chrome/test/data/webui/glic/api_test.ts
+++ b/chrome/test/data/webui/glic/api_test.ts
@@ -660,6 +660,20 @@
     assertFalse(result.pdfDocumentData!.pdfSizeLimitExceeded);
   }
 
+  async testGetContextForActorFromFocusedTabWithoutPermission() {
+    await this.host.setTabContextPermissionState(true);
+    assertTrue(!!this.host.getFocusedTabStateV2);
+    const focusedTab = await this.host.getFocusedTabStateV2().getCurrentValue();
+    assertTrue(!!focusedTab?.hasFocus?.tabData?.tabId);
+    await this.host.setTabContextPermissionState(false);
+    const result = await this.host.getContextForActorFromTab?.(
+        focusedTab.hasFocus.tabData.tabId, {});
+    assertTrue(!!result);
+  }
+
+  // TODO(crbug.com/422544382): add test for getContextForActorFromTab for the
+  // case where tab is in background.
+
   // TODO(harringtond): This is disabled because it hangs. Fix it.
   async testCaptureScreenshot() {
     assertTrue(!!this.host.captureScreenshot);
diff --git a/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts
index 4945736..6b0fea4 100644
--- a/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts
+++ b/chrome/test/data/webui/new_tab_page/modules/v2/tab_groups/module_test.ts
@@ -3,24 +3,76 @@
 // found in the LICENSE file.
 
 import type {TabGroupsModuleElement} from 'chrome://new-tab-page/lazy_load.js';
-import {tabGroupsDescriptor} from 'chrome://new-tab-page/lazy_load.js';
-import {assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {tabGroupsDescriptor, TabGroupsProxyImpl} from 'chrome://new-tab-page/lazy_load.js';
+import {PageHandlerRemote} from 'chrome://new-tab-page/tab_groups.mojom-webui.js';
+import type {TabGroup} from 'chrome://new-tab-page/tab_groups.mojom-webui.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import type {TestMock} from 'chrome://webui-test/test_mock.js';
 import {isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js';
 
-suite('NewTabPageModulesTabGroupsModuleTest', () => {
-  let module: TabGroupsModuleElement;
+import {installMock} from '../../../test_support.js';
 
-  setup(async () => {
+suite('NewTabPageModulesTabGroupsModuleTest', () => {
+  let handler: TestMock<PageHandlerRemote>;
+
+  setup(() => {
+    handler = installMock(
+        PageHandlerRemote,
+        mock => TabGroupsProxyImpl.setInstance(new TabGroupsProxyImpl(mock)));
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    module = await tabGroupsDescriptor.initialize(0) as TabGroupsModuleElement;
-    document.body.append(module);
-    return microtasksFinished();
   });
 
-  test('creates module', () => {
+  async function createModule(tabGroups: TabGroup[]):
+      Promise<TabGroupsModuleElement> {
+    handler.setResultFor('getTabGroups', Promise.resolve({tabGroups}));
+    const module =
+        await tabGroupsDescriptor.initialize(0) as TabGroupsModuleElement;
+    document.body.append(module);
+    await microtasksFinished();
+    return module;
+  }
+
+  test('No module created if no tab groups data', async () => {
+    const module = await createModule([]);
+    assertEquals(null, module);
+  });
+
+  test('creates module', async () => {
+    // Arrange.
+    const tabGroups: TabGroup[] = [
+      {
+        title: 'Tab Group 1',
+        url: {url: 'http://www.google.com/'},
+      },
+      {
+        title: 'Tab Group 2',
+        url: {url: 'http://www.google.com/'},
+      },
+    ];
+    const module = await createModule(tabGroups);
+
     // Assert.
+    // Verify the module was created and is visible.
     assertTrue(!!module);
     assertTrue(
         isVisible(module.shadowRoot.querySelector('ntp-module-header-v2')));
+
+    // Verify the tab groups info is correct.
+    const groups =
+        module.shadowRoot.querySelectorAll<HTMLAnchorElement>('.tab-group');
+    assertTrue(!!groups);
+    assertEquals(tabGroups.length, groups.length);
+
+    assertTrue(!!groups[0]);
+    assertEquals(
+        'Tab Group 1',
+        groups[0].querySelector('.tab-group-title')!.textContent);
+    assertEquals('http://www.google.com/', groups[0].href);
+
+    assertTrue(!!groups[1]);
+    assertEquals(
+        'Tab Group 2',
+        groups[1].querySelector('.tab-group-title')!.textContent);
+    assertEquals('http://www.google.com/', groups[1].href);
   });
 });
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc
index 0978a3d..62b0e125 100644
--- a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc
+++ b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.cc
@@ -69,7 +69,7 @@
   RunTest("new_tab_page/composebox/file_carousel_test.js", "mocha.run()");
 }
 
-IN_PROC_BROWSER_TEST_F(NewTabPageTest, ComposeboxFileThumbnail) {
+IN_PROC_BROWSER_TEST_F(NewTabPageTest, DISABLED_ComposeboxFileThumbnail) {
   RunTest("new_tab_page/composebox/file_thumbnail_test.js", "mocha.run()");
 }
 
diff --git a/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_test.ts b/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_test.ts
index 7d5e906..3e00fb5 100644
--- a/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_test.ts
+++ b/chrome/test/data/webui/privacy_sandbox/internals/privacy_sandbox_internals_test.ts
@@ -115,6 +115,91 @@
   });
 });
 
+// Test suite for Sidebar behavior within the live InternalsPage.
+suite('PrivacySandboxInternalsFrameListTest', function() {
+  let page: InternalsPage;
+  let shadowRoot: ShadowRoot;
+  let browserProxy: TestPrivacySandboxInternalsBrowserProxy;
+
+  setup(async function() {
+    browserProxy = new TestPrivacySandboxInternalsBrowserProxy();
+    browserProxy.testHandler.setPrefs([]);
+    PrivacySandboxInternalsBrowserProxy.setInstance(browserProxy);
+    Router.resetInstanceForTesting();
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    page = document.createElement('internals-page');
+    document.body.appendChild(page);
+    shadowRoot = page.shadowRoot!;
+    await waitForElement(shadowRoot, '[data-page-name="cookies"]');
+    await microtasksFinished();
+  });
+
+  test('SettingsCategoryHeaderCollapsesAndExpandsOnClick', async () => {
+    const prefsHeader = shadowRoot.querySelector<HTMLElement>(
+        'div[role="heading"].settings-category-header');
+    assertTrue(!!prefsHeader, 'The "Prefs" header should exist.');
+
+    assertFalse(
+        prefsHeader.hasAttribute('collapsed'),
+        'Prefs header should be expanded initially.');
+
+    prefsHeader.click();
+    await microtasksFinished();
+    assertTrue(
+        prefsHeader.hasAttribute('collapsed'),
+        'Prefs header should collapse after click.');
+  });
+
+  test('clickingGroupHeaderTogglesCollapseAndHidesSubGroup', async () => {
+    const groupHeaders = shadowRoot.querySelectorAll<HTMLElement>(
+        'div[role="heading"].settings-category-header');
+    assertEquals(2, groupHeaders.length, 'Should find two main group headers');
+    const contentSettingsHeader = groupHeaders[1]!;
+    const subGroupHeader = shadowRoot.querySelector<HTMLElement>(
+        'div[role="heading"].setting-header');
+    assertTrue(!!subGroupHeader, 'Sub-group header should exist.');
+
+    assertFalse(
+        contentSettingsHeader.hasAttribute('collapsed'),
+        'Content Settings header should be expanded by default.');
+    assertFalse(
+        subGroupHeader.hasAttribute('collapsed'),
+        'Sub-group header should be expanded by default.');
+
+    assertTrue(
+        !!subGroupHeader.offsetParent,
+        'Sub-group should be rendered initially.');
+
+    contentSettingsHeader.click();
+    await microtasksFinished();
+
+    assertTrue(
+        contentSettingsHeader.hasAttribute('collapsed'),
+        'Content Settings header should collapse after click.');
+    assertEquals(
+        null, subGroupHeader.offsetParent,
+        'Sub-group should become hidden when parent collapses.');
+
+    contentSettingsHeader.click();
+    await microtasksFinished();
+
+    assertFalse(
+        contentSettingsHeader.hasAttribute('collapsed'),
+        'Content Settings header should re-expand.');
+    assertTrue(
+        !!subGroupHeader.offsetParent, 'Sub-group should be visible again.');
+    assertFalse(
+        subGroupHeader.hasAttribute('collapsed'),
+        'Sub-group header should have retained its expanded state.');
+
+    subGroupHeader.click();
+    await microtasksFinished();
+    assertTrue(
+        subGroupHeader.hasAttribute('collapsed'),
+        'Sub-group header should collapse after its own click.');
+  });
+});
+
 // Test suite for routing within the Privacy Sandbox Internals page.
 suite('PrivacySandboxInternalsRoutingTest', function() {
   let page: InternalsPage;
@@ -145,8 +230,13 @@
   });
 
   test('defaultsToFirstTabOnLoad', async function() {
+    const allTabs =
+        Array.from(shadowRoot.querySelectorAll<HTMLElement>('[slot="tab"]'));
+    const firstSelectableTab =
+        allTabs.find((tab) => tab.getAttribute('role') !== 'heading');
+    const expectedIndex = allTabs.indexOf(firstSelectableTab!).toString();
     await waitForCondition(
-        () => tabContainer.getAttribute('selected-index') === '0');
+        () => tabContainer.getAttribute('selected-index') === expectedIndex);
     const params = new URLSearchParams(window.location.search);
     assertEquals(Page.TRACKING_PROTECTION, params.get('page'));
   });
@@ -191,8 +281,16 @@
     shadowRoot = page.shadowRoot!;
     tabContainer = await waitForElement(shadowRoot, '#ps-page');
 
+    const allTabs =
+        Array.from(shadowRoot.querySelectorAll<HTMLElement>('[slot="tab"]'));
+    const firstSelectableTab =
+        allTabs.find((tab) => tab.getAttribute('role') !== 'heading');
+
+    const expectedIndex = allTabs.indexOf(firstSelectableTab!).toString();
+
     await waitForCondition(
-        () => tabContainer.getAttribute('selected-index') === '0');
+        () => tabContainer.getAttribute('selected-index') === expectedIndex);
+
     const params = new URLSearchParams(window.location.search);
     assertEquals(
         Page.TRACKING_PROTECTION, params.get('page'),
@@ -200,8 +298,15 @@
   });
 
   test('defaultsToFirstTabWhenNoPageInUrl', async function() {
+    const allTabs =
+        Array.from(shadowRoot.querySelectorAll<HTMLElement>('[slot="tab"]'));
+    const firstSelectableTab =
+        allTabs.find((tab) => tab.getAttribute('role') !== 'heading');
+
+    const expectedIndex = allTabs.indexOf(firstSelectableTab!).toString();
+
     await waitForCondition(
-        () => tabContainer.getAttribute('selected-index') === '0');
+        () => tabContainer.getAttribute('selected-index') === expectedIndex);
     const params = new URLSearchParams(window.location.search);
     assertEquals(
         Page.TRACKING_PROTECTION, params.get('page'),
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index e0e2d06b..1f76b1f5 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -71,6 +71,7 @@
     "payments_section_payments_list_test.ts",
     "payments_section_test.ts",
     "payments_section_utils.ts",
+    "people_page_index_test.ts",
     "people_page_sync_controls_test.ts",
     "people_page_sync_page_interactive_test.ts",
     "people_page_sync_page_test.ts",
diff --git a/chrome/test/data/webui/settings/account_page_test.ts b/chrome/test/data/webui/settings/account_page_test.ts
index cf3868d7..360bf9c 100644
--- a/chrome/test/data/webui/settings/account_page_test.ts
+++ b/chrome/test/data/webui/settings/account_page_test.ts
@@ -4,20 +4,27 @@
 
 import 'chrome://settings/lazy_load.js';
 
+import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 import type {SettingsAccountPageElement} from 'chrome://settings/lazy_load.js';
-import {loadTimeData, Router, routes, SignedInState, StatusAction} from 'chrome://settings/settings.js';
+import {loadTimeData, Router, routes, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js';
 import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {microtasksFinished} from 'chrome://webui-test/test_util.js';
 
+import {TestSyncBrowserProxy} from './test_sync_browser_proxy.js';
+
 
 suite('AccountPageTests', function() {
   let accountSettingsPage: SettingsAccountPageElement;
+  let testSyncBrowserProxy: TestSyncBrowserProxy;
 
   setup(function() {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
 
     loadTimeData.overrideValues({replaceSyncPromosWithSignInPromos: true});
 
+    testSyncBrowserProxy = new TestSyncBrowserProxy();
+    SyncBrowserProxyImpl.setInstance(testSyncBrowserProxy);
+
     accountSettingsPage = createSettingsAccountPageElement();
     Router.getInstance().navigateTo(routes.ACCOUNT);
 
@@ -26,7 +33,7 @@
 
   function createSettingsAccountPageElement(): SettingsAccountPageElement {
     const element = document.createElement('settings-account-page');
-    element.syncStatus = {
+    testSyncBrowserProxy.testSyncStatus = {
       signedInState: SignedInState.SIGNED_IN,
       statusAction: StatusAction.NO_ACTION,
     };
@@ -47,28 +54,10 @@
   // Tests that we navigate back to the people page if the user is not signed
   // in.
   test('accountSettingsPageUnavailableWhenNotSignedIn', async function() {
-    accountSettingsPage.syncStatus = {
+    webUIListenerCallback('sync-status-changed', {
       signedInState: SignedInState.SIGNED_OUT,
       statusAction: StatusAction.NO_ACTION,
-    };
-    await microtasksFinished();
-
-    assertEquals(routes.PEOPLE, Router.getInstance().getCurrentRoute());
-  });
-
-  // Tests that we navigate back to the people page if the flag is disabled.
-  test('accountSettingsPageUnavailableWithoutFlag', async function() {
-    loadTimeData.overrideValues({replaceSyncPromosWithSignInPromos: false});
-
-    // Recreate the element with the flag disabled and trigger a call to
-    // `syncStatusChanged_`.
-    document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    accountSettingsPage = createSettingsAccountPageElement();
-    Router.getInstance().navigateTo(routes.ACCOUNT);
-    accountSettingsPage.syncStatus = {
-      signedInState: SignedInState.SIGNED_IN,
-      statusAction: StatusAction.NO_ACTION,
-    };
+    });
     await microtasksFinished();
 
     assertEquals(routes.PEOPLE, Router.getInstance().getCurrentRoute());
diff --git a/chrome/test/data/webui/settings/basic_page_test.ts b/chrome/test/data/webui/settings/basic_page_test.ts
index 4028790..f80332e 100644
--- a/chrome/test/data/webui/settings/basic_page_test.ts
+++ b/chrome/test/data/webui/settings/basic_page_test.ts
@@ -285,17 +285,15 @@
     document.body.appendChild(page);
     page.scroller = document.body;
 
-    // Need to wait for the 'show-container' event to fire after every
-    // transition, to ensure no logic related to previous transitions is still
-    // running when later transitions are tested.
-    const whenDone = eventToPromise('show-container', page);
-
     // Ensure that all settings-section instances are rendered.
     flush();
     const sections = page.shadowRoot!.querySelectorAll('settings-section');
     assertTrue(sections.length > 1);
 
+    const whenDone = eventToPromise('show-container', page);
+    Router.getInstance().navigateTo(routes.PRIVACY);
     await whenDone;
+    return microtasksFinished();
   });
 
   test('load page', function() {
@@ -305,10 +303,6 @@
   // Same as the SometimesMoreSectionsShown test in the suite above, but
   // including the privacy guide.
   test('SometimesMoreSectionsShownWithPrivacyGuide', async function() {
-    const whenDone = eventToPromise('show-container', page);
-    Router.getInstance().navigateTo(routes.PRIVACY);
-    await whenDone;
-    await microtasksFinished();
     await privacyGuideBrowserProxy.whenCalled('incrementPromoImpressionCount');
 
     const activeSections =
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 73d8076..fe37167 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
@@ -43,6 +43,7 @@
     MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
 
     setClearBrowsingDataPrefs(false);
+    loadTimeData.overrideValues({showGlicSettings: true});
     return createDialog();
   });
 
diff --git a/chrome/test/data/webui/settings/other_google_data_dialog_test.ts b/chrome/test/data/webui/settings/other_google_data_dialog_test.ts
index 1afa97e..c30a1ee 100644
--- a/chrome/test/data/webui/settings/other_google_data_dialog_test.ts
+++ b/chrome/test/data/webui/settings/other_google_data_dialog_test.ts
@@ -34,10 +34,17 @@
     MetricsBrowserProxyImpl.setInstance(testMetricsBrowserProxy);
 
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    loadTimeData.overrideValues({
+      showGlicSettings: true,
+    });
+    return createDialog();
+  });
+
+  function createDialog() {
     dialog = document.createElement('settings-other-google-data-dialog');
     document.body.appendChild(dialog);
     return flushTasks();
-  });
+  }
 
   function setSignedInAndDseState(
       signedInState: SignedInState, isGoogleDse: boolean,
@@ -205,24 +212,29 @@
 
   test('LinkRowsCssClass', async function() {
     // Case 1: User is signed in and Google is DSE, passwords > Google search
-    // history > my activity rows should be shown in this order.
+    // history > my activity > Gemini Apps rows should be shown in this order.
     setSignedInAndDseState(SignedInState.SIGNED_IN, /*isGoogleDse=*/ true);
     await flushTasks();
     assertTrue(
         dialog.$.passwordManagerLink.classList.contains('first-link-row'));
     assertTrue(
         dialog.$.googleSearchHistoryLink.classList.contains('middle-link-row'));
-    assertTrue(dialog.$.myActivityLink.classList.contains('last-link-row'));
+    assertTrue(dialog.$.myActivityLink.classList.contains('middle-link-row'));
+    assertTrue(
+        dialog.$.geminiAppsActivityLink.classList.contains('last-link-row'));
     assertFalse(isVisible(dialog.$.nonGoogleSearchHistoryLink));
 
     // Case 2: User is signed in and Google is not the DSE, passwords  > my
-    // activity > non Google search history rows should be shown in this order.
+    // activity > Gemini Apps>non Google search history rows should be shown in
+    // this order.
     setSignedInAndDseState(SignedInState.SIGNED_IN, /*isGoogleDse=*/ false);
     await flushTasks();
     assertTrue(
         dialog.$.passwordManagerLink.classList.contains('first-link-row'));
     assertFalse(isVisible(dialog.$.googleSearchHistoryLink));
     assertTrue(dialog.$.myActivityLink.classList.contains('middle-link-row'));
+    assertTrue(
+        dialog.$.geminiAppsActivityLink.classList.contains('middle-link-row'));
     assertTrue(dialog.$.nonGoogleSearchHistoryLink.classList.contains(
         'last-link-row'));
 
@@ -234,6 +246,7 @@
         dialog.$.passwordManagerLink.classList.contains('first-link-row'));
     assertFalse(isVisible(dialog.$.googleSearchHistoryLink));
     assertFalse(isVisible(dialog.$.myActivityLink));
+    assertFalse(isVisible(dialog.$.geminiAppsActivityLink));
     assertTrue(dialog.$.nonGoogleSearchHistoryLink.classList.contains(
         'last-link-row'));
 
@@ -245,6 +258,52 @@
         dialog.$.passwordManagerLink.classList.contains('only-link-row'));
     assertFalse(isVisible(dialog.$.googleSearchHistoryLink));
     assertFalse(isVisible(dialog.$.myActivityLink));
+    assertFalse(isVisible(dialog.$.geminiAppsActivityLink));
     assertFalse(isVisible(dialog.$.nonGoogleSearchHistoryLink));
+
+    // Case 5: Gemini Activity row is not shown. Google is not DSE.
+    loadTimeData.overrideValues({
+      showGlicSettings: false,
+    });
+    await createDialog();
+    setSignedInAndDseState(SignedInState.SIGNED_IN, /*isGoogleDse=*/ true);
+    await flushTasks();
+
+    assertTrue(
+        dialog.$.passwordManagerLink.classList.contains('first-link-row'));
+    assertTrue(
+        dialog.$.googleSearchHistoryLink.classList.contains('middle-link-row'));
+    assertTrue(dialog.$.myActivityLink.classList.contains('last-link-row'));
+    assertFalse(isVisible(dialog.$.geminiAppsActivityLink));
+    assertFalse(isVisible(dialog.$.nonGoogleSearchHistoryLink));
+  });
+
+  test('GeminiAppsActivityLinkClick', async function() {
+    setSignedInAndDseState(SignedInState.SIGNED_IN, /*isGoogleDse=*/ true);
+    await flushTasks();
+
+    assertTrue(isVisible(dialog.$.geminiAppsActivityLink));
+    dialog.$.geminiAppsActivityLink.click();
+
+    const url = await testOpenWindowProxy.whenCalled('openUrl');
+    assertEquals(loadTimeData.getString('myActivityGeminiAppsUrl'), url);
+  });
+
+  test('GeminiAppsActivityVisibility', async function() {
+    setSignedInAndDseState(SignedInState.SIGNED_IN, /*isGoogleDse=*/ true);
+    await flushTasks();
+    assertTrue(isVisible(dialog.$.geminiAppsActivityLink));
+
+    setSignedInAndDseState(SignedInState.SIGNED_OUT, /*isGoogleDse=*/ true);
+    await flushTasks();
+    assertFalse(isVisible(dialog.$.geminiAppsActivityLink));
+
+    loadTimeData.overrideValues({
+      showGlicSettings: false,
+    });
+    await createDialog();
+    setSignedInAndDseState(SignedInState.SIGNED_IN, /*isGoogleDse=*/ true);
+    await flushTasks();
+    assertFalse(isVisible(dialog.$.geminiAppsActivityLink));
   });
 });
diff --git a/chrome/test/data/webui/settings/people_page_index_test.ts b/chrome/test/data/webui/settings/people_page_index_test.ts
new file mode 100644
index 0000000..6bcc325
--- /dev/null
+++ b/chrome/test/data/webui/settings/people_page_index_test.ts
@@ -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.
+
+import 'chrome://settings/settings.js';
+import 'chrome://settings/lazy_load.js';
+
+import type {SettingsPeoplePageIndexElement} from 'chrome://settings/settings.js';
+import {CrSettingsPrefs, resetRouterForTesting, Router, routes, SignedInState, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js';
+
+// <if expr="not is_chromeos">
+import {loadTimeData} from 'chrome://settings/settings.js';
+// </if>
+
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+import {microtasksFinished} from 'chrome://webui-test/test_util.js';
+
+import {TestSyncBrowserProxy} from './test_sync_browser_proxy.js';
+
+suite('PeoplePageIndex', function() {
+  let index: SettingsPeoplePageIndexElement;
+
+  async function createPeoplePageIndex(): Promise<void> {
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    const settingsPrefs = document.createElement('settings-prefs');
+    document.body.appendChild(settingsPrefs);
+    await CrSettingsPrefs.initialized;
+    index = document.createElement('settings-people-page-index');
+    index.prefs = settingsPrefs.prefs!;
+    document.body.appendChild(index);
+    return flushTasks();
+  }
+
+  setup(function() {
+    // <if expr="not is_chromeos">
+    loadTimeData.overrideValues({
+      replaceSyncPromosWithSignInPromos: true,
+    });
+    // </if>
+    resetRouterForTesting();
+
+    // Set SignedInState.SIGNED_IN otherwise navigating to routes.SYNC_ADVANCED
+    // would automatically redirect to routes.SYNC.
+    const browserProxy = new TestSyncBrowserProxy();
+    SyncBrowserProxyImpl.setInstance(browserProxy);
+    browserProxy.testSyncStatus = {
+      signedInState: SignedInState.SIGNED_IN,
+      statusAction: StatusAction.NO_ACTION,
+    };
+
+    return createPeoplePageIndex();
+  });
+
+  test('Routing', async function() {
+    function assertActiveView(id: string) {
+      assertTrue(
+          !!index.$.viewManager.querySelector(`#${id}.active[slot=view]`));
+      assertFalse(!!index.$.viewManager.querySelector(
+          `.active[slot=view]:not(#${id})`));
+    }
+
+    assertEquals(routes.BASIC, Router.getInstance().getCurrentRoute());
+    assertActiveView('parent');
+
+    Router.getInstance().navigateTo(routes.SYNC);
+    await microtasksFinished();
+    assertActiveView('sync');
+
+    Router.getInstance().navigateTo(routes.SYNC_ADVANCED);
+    await microtasksFinished();
+    assertActiveView('syncControls');
+
+    // <if expr="not is_chromeos">
+    Router.getInstance().navigateTo(routes.MANAGE_PROFILE);
+    await microtasksFinished();
+    assertActiveView('manageProfile');
+
+    Router.getInstance().navigateTo(routes.ACCOUNT);
+    await microtasksFinished();
+    assertActiveView('account');
+    // </if>
+
+    Router.getInstance().navigateTo(routes.PEOPLE);
+    await microtasksFinished();
+    assertActiveView('parent');
+  });
+
+  // Test that the child views are properly annotated.
+  test('DataParentViewId', function() {
+    const childViewsId = [
+      'sync', 'syncControls',
+      // <if expr="not is_chromeos">
+      'manageProfile', 'account',
+      // </if>
+    ];
+    for (const id of childViewsId) {
+      assertTrue(!!index.$.viewManager.querySelector(
+          `#${id}[slot=view][data-parent-view-id=parent]`));
+    }
+  });
+
+  // Minimal (non-exhaustive) tests to ensure SearchableViewContainerMixin is
+  // inherited correctly.
+  test('Search', async function() {
+    // Test that search finds results in both parent and child views.
+    const result = await index.searchContents('Sync');
+    assertFalse(result.canceled);
+    assertTrue(result.matchCount >= 2);
+    assertFalse(result.wasClearSearch);
+  });
+});
diff --git a/chrome/test/data/webui/settings/route_test.ts b/chrome/test/data/webui/settings/route_test.ts
index 9a9112e0..19dc52b6 100644
--- a/chrome/test/data/webui/settings/route_test.ts
+++ b/chrome/test/data/webui/settings/route_test.ts
@@ -352,6 +352,20 @@
     resetRouterForTesting();
     assertFalse(!!routes.AUTOFILL_AI);
   });
+
+  // <if expr="not is_chromeos">
+  test('account route existence', function() {
+    resetPageVisibilityForTesting({people: true});
+
+    loadTimeData.overrideValues({replaceSyncPromosWithSignInPromos: false});
+    resetRouterForTesting();
+    assertFalse(!!routes.ACCOUNT);
+
+    loadTimeData.overrideValues({replaceSyncPromosWithSignInPromos: true});
+    resetRouterForTesting();
+    assertTrue(!!routes.ACCOUNT);
+  });
+  // </if>
 });
 
 suite('DynamicParameters', function() {
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc
index bcee676..d5b262f 100644
--- a/chrome/test/data/webui/settings/settings_browsertest.cc
+++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -335,6 +335,10 @@
   RunTest("settings/people_page_test.js", "mocha.run()");
 }
 
+IN_PROC_BROWSER_TEST_F(SettingsTest, PeoplePageIndex) {
+  RunTest("settings/people_page_index_test.js", "mocha.run()");
+}
+
 #if BUILDFLAG(IS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(SettingsTest, PeoplePageChromeOS) {
   RunTest("settings/people_page_test_cros.js", "mocha.run()");
@@ -858,9 +862,16 @@
 }
 
 class SettingsClearBrowsingDataV2Test : public SettingsBrowserTest {
+ protected:
+  SettingsClearBrowsingDataV2Test() {
+    scoped_feature_list_.InitWithFeatures(
+        {browsing_data::features::kDbdRevampDesktop,
+         browsing_data::features::kBrowsingHistoryActorIntegrationM1},
+        /*disabled_features=*/{});
+  }
+
  private:
-  base::test::ScopedFeatureList scoped_feature_list_{
-      browsing_data::features::kDbdRevampDesktop};
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 #if !BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/test/data/webui/settings/settings_main_plugins_test.ts b/chrome/test/data/webui/settings/settings_main_plugins_test.ts
index 414cad1..ec8b0775 100644
--- a/chrome/test/data/webui/settings/settings_main_plugins_test.ts
+++ b/chrome/test/data/webui/settings/settings_main_plugins_test.ts
@@ -53,23 +53,10 @@
           `.active[slot=view] > :not(${pluginTag}, dom-if)`));
     }
 
-    // Check routes that are still residing within the old settings-basic-page
-    // "plugin".
-    const nonMigratedRoutes = [
-      routes.BASIC,
-      routes.PRIVACY,
-    ];
-
-    for (const route of nonMigratedRoutes) {
-      Router.getInstance().navigateTo(route);
-      assertActive('settings-basic-page', route.path);
-    }
-
-    // Check routes that have been promoted to individual "plugins".
-    const migratedRoutes: Array<{route: Route, pluginTag: string}> = [
-      // TODO(crbug.com/424223101): Update this list as more routes are
-      // migrated.
-
+    const routesToVisit: Array<{route: Route, pluginTag: string}> = [
+      {route: routes.PEOPLE, pluginTag: 'settings-people-page-index'},
+      {route: routes.BASIC, pluginTag: 'settings-people-page-index'},
+      {route: routes.PRIVACY, pluginTag: 'settings-basic-page'},
       {route: routes.AUTOFILL, pluginTag: 'settings-autofill-page-index'},
       {route: routes.PERFORMANCE, pluginTag: 'settings-performance-page-index'},
       {route: routes.APPEARANCE, pluginTag: 'settings-appearance-page-index'},
@@ -91,7 +78,7 @@
       {route: routes.ABOUT, pluginTag: 'settings-about-page'},
     ];
 
-    for (const {route, pluginTag} of migratedRoutes) {
+    for (const {route, pluginTag} of routesToVisit) {
       Router.getInstance().navigateTo(route);
       await flushTasks();
       assertActive(pluginTag, route.path);
@@ -132,7 +119,7 @@
     function assertVisibilityRespected() {
       const viewIds: string[] = [
         'a11y', 'about', 'appearance', 'downloads', 'languages', 'onStartup',
-        'performance', 'reset', 'search',
+        'people', 'performance', 'reset', 'search',
 
         // <if expr='not is_chromeos'>
         'defaultBrowser', 'system',
@@ -176,13 +163,14 @@
   });
 
   // Test which section is displayed when chrome://settings/ is visited.
-  test('TopLevelRoute', function() {
+  test('TopLevelRoute', async function() {
+    await flushTasks();
     // Case1: Default (non-guest mode)
     assertFalse(loadTimeData.getBoolean('isGuest'));
     let active = settingsMain.$.switcher.querySelector<HTMLElement>(
         '.active[slot=view]');
     assertTrue(!!active);
-    assertEquals('old', active.id);
+    assertEquals('people', active.id);
 
     // Case2: Guest mode.
     loadTimeData.overrideValues({isGuest: true});
diff --git a/chrome/test/data/webui/side_panel/read_anything/BUILD.gn b/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
index 6208f98..70b0e8e 100644
--- a/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/read_anything/BUILD.gn
@@ -23,7 +23,7 @@
     "font_menu_test.ts",
     "font_size_test.ts",
     "highlight_menu_test.ts",
-    "highlight_toggle_test.ts",
+    "phrase_highlight_menu_test.ts",
     "highlighter_test.ts",
     "image_test.ts",
     "images_toggle_button_test.ts",
diff --git a/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts
index e6493e3..c0918a5 100644
--- a/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/highlight_menu_test.ts
@@ -25,7 +25,6 @@
     const readingMode = new FakeReadingMode();
     chrome.readingMode = readingMode as unknown as typeof chrome.readingMode;
     chrome.readingMode.isReadAloudEnabled = true;
-    chrome.readingMode.isPhraseHighlightingEnabled = true;
 
     app = await createApp();
 
@@ -73,8 +72,8 @@
           menu.querySelectorAll<HTMLButtonElement>('.dropdown-item'));
     });
 
-    test('has 5 items', () => {
-      assertEquals(options.length, 5);
+    test('has 4 items', () => {
+      assertEquals(options.length, 4);
     });
 
     test('selects highlight granularity', async () => {
@@ -82,13 +81,17 @@
       for (const option of options) {
         option.click();
         await microtasksFinished();
+        // Skip phrase highlighting, since it's not shown in this menu.
+        if (index === chrome.readingMode.phraseHighlighting) {
+          index += 1;
+        }
         assertEquals(chrome.readingMode.highlightGranularity, index);
         index++;
       }
     });
 
     test('highlight off changes icon', async () => {
-      options[4]!.click();
+      options[3]!.click();
       await microtasksFinished();
       assertEquals('read-anything:highlight-off', highlightButton.ironIcon);
     });
diff --git a/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts b/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts
deleted file mode 100644
index 88271c96..0000000
--- a/chrome/test/data/webui/side_panel/read_anything/highlight_toggle_test.ts
+++ /dev/null
@@ -1,84 +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 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-
-import {BrowserProxy} from '//resources/cr_components/color_change_listener/browser_proxy.js';
-import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
-import type {ReadAnythingToolbarElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import {ToolbarEvent} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import {assertEquals, assertFalse, assertNotEquals, assertStringContains, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
-
-import {createApp} from './common.js';
-import {FakeReadingMode} from './fake_reading_mode.js';
-import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js';
-
-suite('HighlightToggle', () => {
-  let app: AppElement;
-  let toolbar: ReadAnythingToolbarElement;
-  let highlightButton: CrIconButtonElement;
-  let highlightEmitted: boolean;
-
-  setup(async () => {
-    // Clearing the DOM should always be done first.
-    document.body.innerHTML = window.trustedTypes!.emptyHTML;
-    BrowserProxy.setInstance(new TestColorUpdaterBrowserProxy());
-    const readingMode = new FakeReadingMode();
-    chrome.readingMode = readingMode as unknown as typeof chrome.readingMode;
-    chrome.readingMode.isReadAloudEnabled = true;
-    app = await createApp();
-
-    toolbar = app.$.toolbar;
-    highlightButton =
-        toolbar.$.toolbarContainer.querySelector<CrIconButtonElement>(
-            '#highlight')!;
-
-    assertNotEquals(toolbar, null, 'toolbar null');
-    assertNotEquals(highlightButton, null, 'highlight button null');
-
-    highlightEmitted = false;
-    document.addEventListener(
-        ToolbarEvent.HIGHLIGHT_CHANGE, () => highlightEmitted = true);
-  });
-
-  suite('by default', () => {
-    test('highlighting is on', () => {
-      assertEquals('read-anything:highlight-on', highlightButton.ironIcon);
-      assertStringContains(highlightButton.title, 'off');
-      assertEquals(0, chrome.readingMode.highlightGranularity);
-      assertTrue(chrome.readingMode.isHighlightOn());
-      assertFalse(highlightEmitted);
-    });
-  });
-
-  suite('on first click', () => {
-    setup(() => {
-      highlightButton.click();
-    });
-
-    test('highlighting is turned off', () => {
-      assertEquals('read-anything:highlight-off', highlightButton.ironIcon);
-      assertStringContains(highlightButton.title, 'on');
-      assertEquals(
-          chrome.readingMode.noHighlighting,
-          chrome.readingMode.highlightGranularity);
-      assertFalse(chrome.readingMode.isHighlightOn());
-      assertTrue(highlightEmitted);
-    });
-
-    suite('on next click', () => {
-      setup(() => {
-        highlightButton.click();
-      });
-
-      test('highlighting is turned back on', () => {
-        assertEquals('read-anything:highlight-on', highlightButton.ironIcon);
-        assertStringContains(highlightButton.title, 'off');
-        assertEquals(0, chrome.readingMode.highlightGranularity);
-        assertTrue(chrome.readingMode.isHighlightOn());
-        assertTrue(highlightEmitted);
-      });
-    });
-  });
-});
diff --git a/chrome/test/data/webui/side_panel/read_anything/phrase_highlight_menu_test.ts b/chrome/test/data/webui/side_panel/read_anything/phrase_highlight_menu_test.ts
new file mode 100644
index 0000000..0c971a03
--- /dev/null
+++ b/chrome/test/data/webui/side_panel/read_anything/phrase_highlight_menu_test.ts
@@ -0,0 +1,96 @@
+// 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 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+
+import {BrowserProxy} from '//resources/cr_components/color_change_listener/browser_proxy.js';
+import type {CrIconButtonElement} from '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
+import type {AppElement, ReadAnythingToolbarElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {assertEquals, assertStringContains, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
+import {microtasksFinished} from 'chrome-untrusted://webui-test/test_util.js';
+
+import {createApp, stubAnimationFrame} from './common.js';
+import {FakeReadingMode} from './fake_reading_mode.js';
+import {TestColorUpdaterBrowserProxy} from './test_color_updater_browser_proxy.js';
+
+suite('HighlightMenuElement', () => {
+  let app: AppElement;
+  let toolbar: ReadAnythingToolbarElement;
+  let highlightButton: CrIconButtonElement;
+
+  setup(async () => {
+    // Clearing the DOM should always be done first.
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    BrowserProxy.setInstance(new TestColorUpdaterBrowserProxy());
+    const readingMode = new FakeReadingMode();
+    chrome.readingMode = readingMode as unknown as typeof chrome.readingMode;
+    chrome.readingMode.isReadAloudEnabled = true;
+    chrome.readingMode.isPhraseHighlightingEnabled = true;
+
+    app = await createApp();
+
+    toolbar = app.$.toolbar;
+    highlightButton =
+        toolbar.$.toolbarContainer.querySelector<CrIconButtonElement>(
+            '#highlight')!;
+  });
+
+  test('highlighting is on by default', () => {
+    assertEquals('read-anything:highlight-on', highlightButton.ironIcon);
+    assertStringContains(highlightButton.title, 'Voice');
+    assertEquals(0, chrome.readingMode.highlightGranularity);
+    assertTrue(chrome.readingMode.isHighlightOn());
+  });
+
+  test('preference restore maintains menu highlight state', () => {
+    chrome.readingMode.restoreSettingsFromPrefs();
+    assertEquals('read-anything:highlight-on', highlightButton.ironIcon);
+    assertStringContains(highlightButton.title, 'Voice');
+    assertEquals(0, chrome.readingMode.highlightGranularity);
+    assertTrue(chrome.readingMode.isHighlightOn());
+  });
+
+
+  test('click opens menu', async () => {
+    stubAnimationFrame();
+    highlightButton.click();
+    await microtasksFinished();
+
+    const menu = toolbar.$.highlightMenu.$.menu.$.lazyMenu.get();
+    assertTrue(menu.open);
+  });
+
+  suite('dropdown menu', () => {
+    let options: HTMLButtonElement[];
+
+    setup(async () => {
+      stubAnimationFrame();
+      highlightButton.click();
+      await microtasksFinished();
+      const menu = toolbar.$.highlightMenu.$.menu.$.lazyMenu.get();
+      assertTrue(menu.open);
+      options = Array.from(
+          menu.querySelectorAll<HTMLButtonElement>('.dropdown-item'));
+    });
+
+    test('has 5 items', () => {
+      assertEquals(options.length, 5);
+    });
+
+    test('selects highlight granularity', async () => {
+      let index = 0;
+      for (const option of options) {
+        option.click();
+        await microtasksFinished();
+        assertEquals(chrome.readingMode.highlightGranularity, index);
+        index++;
+      }
+    });
+
+    test('highlight off changes icon', async () => {
+      options[4]!.click();
+      await microtasksFinished();
+      assertEquals('read-anything:highlight-off', highlightButton.ironIcon);
+    });
+  });
+});
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc b/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc
index 59e8e56..408805d 100644
--- a/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc
+++ b/chrome/test/data/webui/side_panel/read_anything/read_anything_browsertest.cc
@@ -269,11 +269,6 @@
                    "mocha.run()");
 }
 
-IN_PROC_BROWSER_TEST_F(ReadAnythingMochaTest, HighlightToggle) {
-  RunSidePanelTest("side_panel/read_anything/highlight_toggle_test.js",
-                   "mocha.run()");
-}
-
 IN_PROC_BROWSER_TEST_F(ReadAnythingMochaTest, Highlighter) {
   RunSidePanelTest("side_panel/read_anything/highlighter_test.js",
                    "mocha.run()");
@@ -304,6 +299,11 @@
                    "mocha.run()");
 }
 
+IN_PROC_BROWSER_TEST_F(ReadAnythingMochaTest, HighlightMenu) {
+  RunSidePanelTest("side_panel/read_anything/highlight_menu_test.js",
+                   "mocha.run()");
+}
+
 class ReadAnythingReadAloudPhraseHighlightingMochaTest
     : public ReadAnythingMochaBrowserTest {
  protected:
@@ -320,7 +320,7 @@
 
 IN_PROC_BROWSER_TEST_F(ReadAnythingReadAloudPhraseHighlightingMochaTest,
                        HighlightMenu) {
-  RunSidePanelTest("side_panel/read_anything/highlight_menu_test.js",
+  RunSidePanelTest("side_panel/read_anything/phrase_highlight_menu_test.js",
                    "mocha.run()");
 }
 
diff --git a/chrome/tools/convert_dict/aff_reader.cc b/chrome/tools/convert_dict/aff_reader.cc
index 38f5f26d..932ba30c8 100644
--- a/chrome/tools/convert_dict/aff_reader.cc
+++ b/chrome/tools/convert_dict/aff_reader.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/tools/convert_dict/aff_reader.h"
 
 #include <stddef.h>
 
 #include <algorithm>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/i18n/icu_string_conversions.h"
 #include "base/logging.h"
@@ -29,12 +25,13 @@
 // NULL-terminated ASCII string.
 bool StringBeginsWith(const std::string& str, const char* with) {
   size_t cur = 0;
-  while (cur < str.size() && with[cur] != 0) {
-    if (str[cur] != with[cur])
+  while (cur < str.size() && UNSAFE_TODO(with[cur]) != 0) {
+    if (str[cur] != UNSAFE_TODO(with[cur])) {
       return false;
+    }
     cur++;
   }
-  return with[cur] == 0;
+  return UNSAFE_TODO(with[cur]) == 0;
 }
 
 // Collapses runs of spaces to only one space.
diff --git a/chrome/tools/convert_dict/convert_dict_unittest.cc b/chrome/tools/convert_dict/convert_dict_unittest.cc
index 1468c2e2..ea6bca88 100644
--- a/chrome/tools/convert_dict/convert_dict_unittest.cc
+++ b/chrome/tools/convert_dict/convert_dict_unittest.cc
@@ -2,16 +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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <stddef.h>
 
 #include <map>
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
@@ -52,7 +48,8 @@
     // Check the individual affix indices.
     for (size_t affix_index = 0; affix_index < org_words[i].second.size();
          affix_index++) {
-      EXPECT_EQ(affix_ids[affix_index], org_words[i].second[affix_index]);
+      UNSAFE_TODO(
+          EXPECT_EQ(affix_ids[affix_index], org_words[i].second[affix_index]));
     }
   }
 
@@ -150,7 +147,7 @@
 
   std::map<std::u16string, bool> word_list;
   for (size_t i = 0; i < std::size(kWords); ++i) {
-    word_list.insert({base::WideToUTF16(kWords[i]), true});
+    word_list.insert({base::WideToUTF16(UNSAFE_TODO(kWords[i])), true});
   }
 
   RunDictionaryTest(kCodepage, word_list);
@@ -172,7 +169,7 @@
 
   std::map<std::u16string, bool> word_list;
   for (size_t i = 0; i < std::size(kWords); ++i) {
-    word_list.insert({base::WideToUTF16(kWords[i]), true});
+    word_list.insert({base::WideToUTF16(UNSAFE_TODO(kWords[i])), true});
   }
 
   RunDictionaryTest(kCodepage, word_list);
@@ -196,7 +193,7 @@
 
   std::map<std::u16string, bool> word_list;
   for (size_t i = 0; i < std::size(kWords); ++i) {
-    word_list.insert({base::WideToUTF16(kWords[i]), true});
+    word_list.insert({base::WideToUTF16(UNSAFE_TODO(kWords[i])), true});
   }
 
   RunDictionaryTest(kCodepage, word_list);
diff --git a/chrome/tools/convert_dict/dic_reader.cc b/chrome/tools/convert_dict/dic_reader.cc
index c3775c37..37b6685b 100644
--- a/chrome/tools/convert_dict/dic_reader.cc
+++ b/chrome/tools/convert_dict/dic_reader.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 "chrome/tools/convert_dict/dic_reader.h"
 
 #include <stddef.h>
@@ -14,6 +9,7 @@
 #include <algorithm>
 #include <set>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/strings/string_util.h"
 #include "chrome/tools/convert_dict/aff_reader.h"
@@ -79,8 +75,8 @@
     std::vector<std::string> split;
     SplitDicLine(line, &split);
     if (split.empty() || split.size() > 2) {
-      printf("Line %d has extra slashes in the %s file\n", line_number,
-             file_type);
+      UNSAFE_TODO(printf("Line %d has extra slashes in the %s file\n",
+                         line_number, file_type));
       return false;
     }
 
@@ -91,8 +87,9 @@
     if (encoding_string == "UTF-8") {
       utf8word = split[0];
     } else if (!aff_reader->EncodingToUTF8(split[0], &utf8word)) {
-      printf("Unable to convert line %d from %s to UTF-8 in the %s file\n",
-             line_number, encoding, file_type);
+      UNSAFE_TODO(
+          printf("Unable to convert line %d from %s to UTF-8 in the %s file\n",
+                 line_number, encoding, file_type));
       return false;
     }
 
diff --git a/chrome/tools/convert_dict/hunspell_reader.cc b/chrome/tools/convert_dict/hunspell_reader.cc
index f13e22ed..7cdb729 100644
--- a/chrome/tools/convert_dict/hunspell_reader.cc
+++ b/chrome/tools/convert_dict/hunspell_reader.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 "chrome/tools/convert_dict/hunspell_reader.h"
 
 #include <stddef.h>
 
+#include "base/compiler_specific.h"
 #include "base/strings/string_util.h"
 
 namespace convert_dict {
@@ -34,7 +30,7 @@
 }
 
 std::string ReadLine(FILE* file) {
-  const char* line = fgets(line_buffer, kLineBufferLen - 1, file);
+  const char* line = UNSAFE_TODO(fgets(line_buffer, kLineBufferLen - 1, file));
   if (!line)
     return std::string();
 
diff --git a/chrome/updater/certificate_tag_unittest.cc b/chrome/updater/certificate_tag_unittest.cc
index de5805b..0a29b514 100644
--- a/chrome/updater/certificate_tag_unittest.cc
+++ b/chrome/updater/certificate_tag_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 "chrome/updater/certificate_tag.h"
 
 #include <cstdint>
@@ -49,7 +44,7 @@
   std::optional<std::vector<uint8_t>> parsed_tag(bin2->tag());
   ASSERT_TRUE(parsed_tag);
   ASSERT_EQ(parsed_tag->size(), sizeof(kTag));
-  EXPECT_TRUE(memcmp(kTag, parsed_tag->data(), sizeof(kTag)) == 0);
+  UNSAFE_TODO(EXPECT_TRUE(memcmp(kTag, parsed_tag->data(), sizeof(kTag)) == 0));
 
   // Update an existing tag.
   static constexpr uint8_t kTag2[] = {1, 2, 3, 4, 6};
@@ -61,7 +56,8 @@
   std::optional<std::vector<uint8_t>> parsed_tag2(bin3->tag());
   ASSERT_TRUE(parsed_tag2);
   ASSERT_EQ(parsed_tag2->size(), sizeof(kTag2));
-  EXPECT_TRUE(memcmp(kTag2, parsed_tag2->data(), sizeof(kTag2)) == 0);
+  UNSAFE_TODO(
+      EXPECT_TRUE(memcmp(kTag2, parsed_tag2->data(), sizeof(kTag2)) == 0));
 
   // Updating an existing tag with a tag of the same size should not have grown
   // the binary, i.e. the old tag should have been erased first.
@@ -486,7 +482,8 @@
     for (i = 0; i < bin.sector_format_.size / kNumDirEntryBytes; ++i) {
       uint64_t offset =
           dir_sector * bin.sector_format_.size + i * kNumDirEntryBytes;
-      std::memcpy(&entry, &bin.contents_[offset], sizeof(MSIDirEntry));
+      UNSAFE_TODO(
+          std::memcpy(&entry, &bin.contents_[offset], sizeof(MSIDirEntry)));
 
       // Skip the mini stream and signature entries.
       // SAFETY: byte manipulation of a C data structure.
@@ -533,7 +530,7 @@
 class CertificateTagMsiValidateTest
     : public ::testing::TestWithParam<CertificateTagMsiValidateTestCase> {};
 
-INSTANTIATE_TEST_SUITE_P(
+UNSAFE_TODO(INSTANTIATE_TEST_SUITE_P(
     CertificateTagMsiValidateTestCases,
     CertificateTagMsiValidateTest,
     ::testing::ValuesIn(std::vector<CertificateTagMsiValidateTestCase>{
@@ -570,7 +567,7 @@
            new_tag.resize(8206);
            return new_tag;
          }()},
-    }));
+    })));
 
 TEST_P(CertificateTagMsiValidateTest, TestCases) {
   base::MemoryMappedFile mapped_file;
diff --git a/chrome/updater/ipc/update_service_dialer_linux.cc b/chrome/updater/ipc/update_service_dialer_linux.cc
index 8bba62d..a784996 100644
--- a/chrome/updater/ipc/update_service_dialer_linux.cc
+++ b/chrome/updater/ipc/update_service_dialer_linux.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 "chrome/updater/ipc/update_service_dialer.h"
 
 #include <sys/socket.h>
@@ -15,6 +10,7 @@
 #include <cstdio>
 #include <optional>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
@@ -43,8 +39,8 @@
 
   struct sockaddr_un remote;
   remote.sun_family = AF_UNIX;
-  snprintf(remote.sun_path, sizeof(remote.sun_path), "%s",
-           activation_socket_path.AsUTF8Unsafe().c_str());
+  UNSAFE_TODO(snprintf(remote.sun_path, sizeof(remote.sun_path), "%s",
+                       activation_socket_path.AsUTF8Unsafe().c_str()));
   int len = strlen(remote.sun_path) + sizeof(remote.sun_family);
   if (connect(sock_fd.get(), (struct sockaddr*)&remote, len) == -1) {
     VPLOG(1) << "Could not connect to activation socket";
diff --git a/chrome/utility/importer/nss_decryptor_system_nss.cc b/chrome/utility/importer/nss_decryptor_system_nss.cc
index 8da695b5..81810044 100644
--- a/chrome/utility/importer/nss_decryptor_system_nss.cc
+++ b/chrome/utility/importer/nss_decryptor_system_nss.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/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/utility/importer/nss_decryptor_system_nss.h"
 
 #include <pk11pub.h>
@@ -14,6 +9,7 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
@@ -122,14 +118,14 @@
     goto loser;
   }
 
-  padLength = data->data[data->len-1];
+  padLength = UNSAFE_TODO(data->data[data->len - 1]);
   if (padLength > blockSize) { rv = SECFailure; goto loser; }
 
   /* verify padding */
   for (i = data->len - padLength; static_cast<uint32_t>(i) < data->len; i++) {
-    if (data->data[i] != padLength) {
-        rv = SECFailure;
-        goto loser;
+    if (UNSAFE_TODO(data->data[i]) != padLength) {
+      rv = SECFailure;
+      goto loser;
     }
   }
 
@@ -137,7 +133,7 @@
   result->data = (unsigned char *)PORT_Alloc(result->len);
   if (!result->data) { rv = SECFailure; goto loser; }
 
-  PORT_Memcpy(result->data, data->data, result->len);
+  UNSAFE_TODO(PORT_Memcpy(result->data, data->data, result->len));
 
   if (padLength < 2) {
     return SECWouldBlock;
@@ -197,7 +193,7 @@
   if (!arena) { rv = SECFailure; goto loser; }
 
   /* Decode the incoming data */
-  memset(&sdrResult, 0, sizeof sdrResult);
+  UNSAFE_TODO(memset(&sdrResult, 0, sizeof sdrResult));
   rv = SEC_QuickDERDecodeItem(arena, &sdrResult, g_template, data);
   if (rv != SECSuccess) goto loser;  /* Invalid format */
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index a622b205..9af5ffa 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16358.0.0-1070453
\ No newline at end of file
+16359.0.0-1070472
\ No newline at end of file
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index 7524d79..ee883f3 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-140-7258.43-1753063931-benchmark-140.0.7309.0_pre1489350-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-140-7258.43-1753063931-benchmark-140.0.7314.0_pre1490791-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index d2489f3..0d9f6772 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-140-7258.43-1753070574-benchmark-140.0.7309.0_pre1489350-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-140-7258.43-1753070574-benchmark-140.0.7313.0_pre1490386-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 32a49cf0..9acef52 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-140-7258.33-1753065499-benchmark-140.0.7309.0_pre1489350-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-140-7258.33-1753065499-benchmark-140.0.7313.0_pre1490386-r1-redacted.afdo.xz
diff --git a/chromeos/tast_control_disabled_tests.txt b/chromeos/tast_control_disabled_tests.txt
index d0be1438..e88abced 100644
--- a/chromeos/tast_control_disabled_tests.txt
+++ b/chromeos/tast_control_disabled_tests.txt
@@ -99,4 +99,8 @@
 # b/424789710
 tast.apps.LaunchGalleryFromNotifications.stable
 
+# b/433816171
+tast.secagentd.FileEvents.auth_factors@trogdor
+tast.secagentd.FileEvents.cookies@trogdor
+
 # READ COMMENT AT TOP BEFORE ADDING NEW TESTS HERE.
diff --git a/clank b/clank
index e370bba..004095b 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit e370bba06b3ad6dd18c3f69205c48cd84434ec8f
+Subproject commit 004095b7e48cf8ad46b6380e6f1c3f37e1b0379e
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
index f6bf662a8..ab89c1c9 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -1176,18 +1176,19 @@
       FillingProduct, std::vector<SuggestionGenerator::SuggestionData>>>(
       suggestion_generators_.size(),
       base::BindOnce(&BrowserAutofillManager::OnSuggestionDataFetched,
-                     weak_ptr_factory_.GetWeakPtr(), form.global_id(), field_id,
+                     weak_ptr_factory_.GetWeakPtr(), form, field,
                      trigger_source, context));
 
   for (const auto& suggestion_generator : suggestion_generators_) {
-    suggestion_generator->FetchSuggestionData(*form_structure, *autofill_field,
-                                              client(), barrier_callback);
+    suggestion_generator->FetchSuggestionData(form, field, form_structure,
+                                              autofill_field, client(),
+                                              barrier_callback);
   }
 }
 
 void BrowserAutofillManager::OnSuggestionDataFetched(
-    const FormGlobalId& form_id,
-    const FieldGlobalId& field_id,
+    const FormData& form,
+    const FormFieldData& field,
     AutofillSuggestionTriggerSource trigger_source,
     SuggestionsContext context,
     std::vector<std::pair<FillingProduct,
@@ -1198,21 +1199,21 @@
           suggestion_generators_.size(),
           base::BindOnce(
               &BrowserAutofillManager::OnIndividualSuggestionsGenerated,
-              weak_ptr_factory_.GetWeakPtr(), form_id, field_id, trigger_source,
-              context));
+              weak_ptr_factory_.GetWeakPtr(), form.global_id(),
+              field.global_id(), trigger_source, context));
 
   FormStructure* form_structure = nullptr;
   AutofillField* autofill_field = nullptr;
-  if (!GetCachedFormAndField(form_id, field_id, &form_structure,
-                             &autofill_field)) {
-    // Form is not autofillable, or either the form or the field cannot be
-    // found.
-    return;
-  }
+  // In case we cannot fetch the parsed `FormStructure` and `AutofillField`, we
+  // still need to offer Autocomplete.
+  // TODO(crbug.com/433224307): Consider early returning here when the cache
+  // starts storing all forms and fields.
+  std::ignore = GetCachedFormAndField(form.global_id(), field.global_id(),
+                             &form_structure, &autofill_field);
 
   for (const auto& suggestion_generator : suggestion_generators_) {
-    suggestion_generator->GenerateSuggestions(
-        *form_structure, *autofill_field, suggestion_data, barrier_callback);
+    suggestion_generator->GenerateSuggestions(form, field,
+        form_structure, autofill_field, suggestion_data, barrier_callback);
   }
 }
 
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.h b/components/autofill/core/browser/foundations/browser_autofill_manager.h
index 6e70960..5b7bb962 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.h
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.h
@@ -484,12 +484,13 @@
       SuggestionsContext& context,
       autofill_metrics::SuggestionRankingContext& ranking_context);
 
-  // Called when all suggestion generators have finished fetching their data.
-  // It schedules the generation of the individual suggestions for each
-  // `FillingProduct` and calls `OnIndividualSuggestionsGenerated` when done.
+  // Called when all suggestion generators have finished fetching their data for
+  // the given `field` in `form`. It schedules the generation of the individual
+  // suggestions for each `FillingProduct` and calls
+  // `OnIndividualSuggestionsGenerated` when done.
   void OnSuggestionDataFetched(
-      const FormGlobalId& form_id,
-      const FieldGlobalId& field_id,
+      const FormData& form,
+      const FormFieldData& field,
       AutofillSuggestionTriggerSource trigger_source,
       SuggestionsContext context,
       std::vector<std::pair<FillingProduct,
diff --git a/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl.cc b/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl.cc
index b571648..450c6ca6 100644
--- a/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl.cc
+++ b/components/autofill/core/browser/ml_model/autofill_ai/autofill_ai_model_executor_impl.cc
@@ -56,13 +56,14 @@
 
   // Construct request.
   AutofillAiTypeRequest request;
-  optimization_guide::proto::PageContext* page_context =
-      request.mutable_page_context();
   if (features::kAutofillAiServerModelSendPageUrl.Get()) {
-    page_context->set_url(form_data.url().spec());
+    request.set_url(form_data.url().spec());
   } else {
-    page_context->set_url(form_data.main_frame_origin().Serialize());
+    request.set_url(form_data.main_frame_origin().Serialize());
   }
+  // TODO(crbug.com/389625970): Remove `PageContext` once most clients set
+  // `AutofillAiTypeRequest::url`.
+  request.mutable_page_context()->set_url(request.url());
   *request.mutable_form_data() =
       ToFormDataProto(form_data, FormDataProtoConversionReason::kModelRequest);
 
diff --git a/components/autofill/core/browser/payments/ANDROID_OWNERS b/components/autofill/core/browser/payments/ANDROID_OWNERS
deleted file mode 100644
index b461a73..0000000
--- a/components/autofill/core/browser/payments/ANDROID_OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-vishwasuppoor@google.com
diff --git a/components/autofill/core/browser/payments/iban_manager.cc b/components/autofill/core/browser/payments/iban_manager.cc
index fef4ca3..d99b113 100644
--- a/components/autofill/core/browser/payments/iban_manager.cc
+++ b/components/autofill/core/browser/payments/iban_manager.cc
@@ -54,23 +54,26 @@
   auto on_suggestion_data_returned = base::BindOnce(
       [](base::OnceCallback<void(SuggestionGenerator::ReturnedSuggestions)>
              callback,
-         const FormStructure& form, const AutofillField& autofill_field,
+         const FormFieldData& field, const FormStructure* form,
+         const AutofillField* autofill_field,
          base::WeakPtr<IbanSuggestionGenerator> iban_suggestion_generator,
          std::pair<FillingProduct,
                    std::vector<SuggestionGenerator::SuggestionData>>
              suggestion_data) {
         if (iban_suggestion_generator) {
           iban_suggestion_generator->GenerateSuggestions(
-              form, autofill_field, {suggestion_data}, std::move(callback));
+              form->ToFormData(), field, form, autofill_field,
+              {suggestion_data}, std::move(callback));
         }
       },
-      std::move(on_suggestions_generated), std::cref(form),
-      std::cref(autofill_field), iban_suggestion_generator.GetWeakPtr());
+      std::move(on_suggestions_generated), std::cref(field), &form,
+      &autofill_field, iban_suggestion_generator.GetWeakPtr());
 
   // Since the `on_suggestion_data_returned` callback is called synchronously,
   // we can assume that `suggestions_generated` will hold correct value.
   iban_suggestion_generator.FetchSuggestionData(
-      form, autofill_field, client, std::move(on_suggestion_data_returned));
+      form.ToFormData(), field, &form, &autofill_field, client,
+      std::move(on_suggestion_data_returned));
   return suggestions_generated;
 }
 
diff --git a/components/autofill/core/browser/payments/payments_autofill_client.cc b/components/autofill/core/browser/payments/payments_autofill_client.cc
index 5bbe9d2..7b85497 100644
--- a/components/autofill/core/browser/payments/payments_autofill_client.cc
+++ b/components/autofill/core/browser/payments/payments_autofill_client.cc
@@ -267,6 +267,10 @@
 void PaymentsAutofillClient::ShowCreditCardLocalSaveAndFillDialog(
     CardSaveAndFillDialogCallback callback) {}
 
+void PaymentsAutofillClient::ShowCreditCardUploadSaveAndFillDialog(
+    const LegalMessageLines& legal_message_lines,
+    CardSaveAndFillDialogCallback callback) {}
+
 payments::SaveAndFillManager* PaymentsAutofillClient::GetSaveAndFillManager() {
   return nullptr;
 }
diff --git a/components/autofill/core/browser/payments/payments_autofill_client.h b/components/autofill/core/browser/payments/payments_autofill_client.h
index 041ab2e..f09da85 100644
--- a/components/autofill/core/browser/payments/payments_autofill_client.h
+++ b/components/autofill/core/browser/payments/payments_autofill_client.h
@@ -627,6 +627,11 @@
   virtual void ShowCreditCardLocalSaveAndFillDialog(
       CardSaveAndFillDialogCallback callback);
 
+  // Shows the upload `Save and Fill` modal dialog.
+  virtual void ShowCreditCardUploadSaveAndFillDialog(
+      const LegalMessageLines& legal_message_lines,
+      CardSaveAndFillDialogCallback callback);
+
   // Gets the payments Save and Fill manager owned by the client. This will be
   // used to handle the Save and Fill dialog.
   virtual payments::SaveAndFillManager* GetSaveAndFillManager();
diff --git a/components/autofill/core/browser/payments/save_and_fill_manager.h b/components/autofill/core/browser/payments/save_and_fill_manager.h
index 4c1defe..688967f 100644
--- a/components/autofill/core/browser/payments/save_and_fill_manager.h
+++ b/components/autofill/core/browser/payments/save_and_fill_manager.h
@@ -10,6 +10,10 @@
 // Interface for managing the Save and Fill dialog flow.
 class SaveAndFillManager {
  public:
+  using CardSaveAndFillDialogUserDecision =
+      PaymentsAutofillClient::CardSaveAndFillDialogUserDecision;
+  using UserProvidedCardSaveAndFillDetails =
+      PaymentsAutofillClient::UserProvidedCardSaveAndFillDetails;
   using FillCardCallback = base::OnceCallback<void(const CreditCard&)>;
 
   SaveAndFillManager() = default;
@@ -28,18 +32,16 @@
   // the user in the Save and Fill dialog when the `user_decision` is
   // `kAccepted`.
   virtual void OnUserDidDecideOnLocalSave(
-      PaymentsAutofillClient::CardSaveAndFillDialogUserDecision user_decision,
-      const payments::PaymentsAutofillClient::
-          UserProvidedCardSaveAndFillDetails&
-              user_provided_card_save_and_fill_details) = 0;
+      CardSaveAndFillDialogUserDecision user_decision,
+      const UserProvidedCardSaveAndFillDetails&
+          user_provided_card_save_and_fill_details) = 0;
   // Populates a new credit card object with user provided card details from the
   // Save and Fill dialog. This is called after the user provides credit card
   // information and accepts the dialog.
   virtual void PopulateCreditCardInfo(
-      autofill::CreditCard& card,
-      const payments::PaymentsAutofillClient::
-          UserProvidedCardSaveAndFillDetails&
-              user_provided_card_save_and_fill_details) = 0;
+      CreditCard& card,
+      const UserProvidedCardSaveAndFillDetails&
+          user_provided_card_save_and_fill_details) = 0;
 };
 
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/save_and_fill_manager_impl.cc b/components/autofill/core/browser/payments/save_and_fill_manager_impl.cc
index edab30a..80157fd 100644
--- a/components/autofill/core/browser/payments/save_and_fill_manager_impl.cc
+++ b/components/autofill/core/browser/payments/save_and_fill_manager_impl.cc
@@ -20,11 +20,6 @@
 
 namespace {
 
-using CardSaveAndFillDialogUserDecision =
-    PaymentsAutofillClient::CardSaveAndFillDialogUserDecision;
-using UserProvidedCardSaveAndFillDetails =
-    PaymentsAutofillClient::UserProvidedCardSaveAndFillDetails;
-
 // If set, overrides the return value of IsCreditCardUploadEnabled() for tests.
 std::optional<bool> credit_card_upload_enabled_override_;
 
@@ -141,8 +136,22 @@
     const std::u16string& context_token,
     std::unique_ptr<base::Value::Dict> legal_message,
     std::vector<std::pair<int, int>> supported_card_bin_ranges) {
-  // TODO(crbug.com/378164165): Implement logic to handle the preflight call
-  // response.
+  if (result == PaymentsRpcResult::kSuccess) {
+    LegalMessageLines parsed_legal_message_lines;
+    LegalMessageLine::Parse(*legal_message, &parsed_legal_message_lines,
+                            /*escape_apostrophes=*/true);
+    if (parsed_legal_message_lines.empty()) {
+      // If parsing the legal messages fails, upload Save and Fill should not be
+      // offered. Offer local Save and Fill instead.
+      OfferLocalSaveAndFill();
+      return;
+    }
+    upload_details_.context_token = context_token;
+    OfferUploadSaveAndFill(parsed_legal_message_lines);
+  } else {
+    // If the pre-flight call fails, fall back to offering local Save and Fill.
+    OfferLocalSaveAndFill();
+  }
 }
 
 void SaveAndFillManagerImpl::PopulateInitialUploadDetails() {
@@ -169,4 +178,20 @@
   // separate CL.
 }
 
+void SaveAndFillManagerImpl::OfferUploadSaveAndFill(
+    const LegalMessageLines& parsed_legal_message_lines) {
+  payments_autofill_client()->ShowCreditCardUploadSaveAndFillDialog(
+      std::move(parsed_legal_message_lines),
+      base::BindOnce(&SaveAndFillManagerImpl::OnUserDidDecideOnUploadSave,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SaveAndFillManagerImpl::OnUserDidDecideOnUploadSave(
+    CardSaveAndFillDialogUserDecision user_decision,
+    const UserProvidedCardSaveAndFillDetails&
+        user_provided_card_save_and_fill_details) {
+  // TODO(crbug.com/378164165): Implement logic to handle user decision for
+  // upload Save and Fill dialog.
+}
+
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/save_and_fill_manager_impl.h b/components/autofill/core/browser/payments/save_and_fill_manager_impl.h
index 222f0be..8e3cb43e 100644
--- a/components/autofill/core/browser/payments/save_and_fill_manager_impl.h
+++ b/components/autofill/core/browser/payments/save_and_fill_manager_impl.h
@@ -28,12 +28,12 @@
       FillCardCallback fill_card_callback) override;
   void OfferLocalSaveAndFill() override;
   void OnUserDidDecideOnLocalSave(
-      PaymentsAutofillClient::CardSaveAndFillDialogUserDecision user_decision,
-      const PaymentsAutofillClient::UserProvidedCardSaveAndFillDetails&
+      CardSaveAndFillDialogUserDecision user_decision,
+      const UserProvidedCardSaveAndFillDetails&
           user_provided_card_save_and_fill_details) override;
   void PopulateCreditCardInfo(
       CreditCard& card,
-      const PaymentsAutofillClient::UserProvidedCardSaveAndFillDetails&
+      const UserProvidedCardSaveAndFillDetails&
           user_provided_card_save_and_fill_details) override;
 
   PaymentsAutofillClient* payments_autofill_client() const {
@@ -58,6 +58,17 @@
   // server communication.
   void PopulateInitialUploadDetails();
 
+  // Begins the process to show the upload Save and Fill dialog.
+  void OfferUploadSaveAndFill(
+      const LegalMessageLines& parsed_legal_message_lines);
+
+  // The callback that is invoked after the user makes a decision on the
+  // upload Save and Fill dialog.
+  void OnUserDidDecideOnUploadSave(
+      CardSaveAndFillDialogUserDecision user_decision,
+      const UserProvidedCardSaveAndFillDetails&
+          user_provided_card_save_and_fill_details);
+
   // Reference to the AutofillClient. `autofill_client_` outlives `this`.
   const raw_ref<AutofillClient> autofill_client_;
 
diff --git a/components/autofill/core/browser/payments/save_and_fill_manager_impl_unittest.cc b/components/autofill/core/browser/payments/save_and_fill_manager_impl_unittest.cc
index 8a8bcb0..132cef2 100644
--- a/components/autofill/core/browser/payments/save_and_fill_manager_impl_unittest.cc
+++ b/components/autofill/core/browser/payments/save_and_fill_manager_impl_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/autofill/core/browser/payments/save_and_fill_manager_impl.h"
 
+#include "base/json/json_reader.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
@@ -27,6 +28,30 @@
 using UserProvidedCardSaveAndFillDetails =
     PaymentsAutofillClient::UserProvidedCardSaveAndFillDetails;
 
+constexpr char kLegalMessageLines[] =
+    "{"
+    "  \"line\" : [ {"
+    "     \"template\": \"The legal documents are: {0} and {1}.\","
+    "     \"template_parameter\" : [ {"
+    "        \"display_text\" : \"Terms of Service\","
+    "        \"url\": \"http://www.example.com/tos\""
+    "     }, {"
+    "        \"display_text\" : \"Privacy Policy\","
+    "        \"url\": \"http://www.example.com/pp\""
+    "     } ]"
+    "  } ]"
+    "}";
+
+constexpr char kInvalidLegalMessageLines[] =
+    "{"
+    "  \"line\" : [ {"
+    "     \"template\": \"Panda {0}.\","
+    "     \"template_parameter\": [ {"
+    "        \"display_text\": \"bear\""
+    "     } ]"
+    "  } ]"
+    "}";
+
 class TestPaymentsAutofillClientMock : public TestPaymentsAutofillClient {
  public:
   explicit TestPaymentsAutofillClientMock(autofill::AutofillClient* client)
@@ -40,6 +65,11 @@
       (base::OnceCallback<void(CardSaveAndFillDialogUserDecision,
                                const UserProvidedCardSaveAndFillDetails&)>),
       (override));
+
+  MOCK_METHOD(void,
+              ShowCreditCardUploadSaveAndFillDialog,
+              (const LegalMessageLines&, CardSaveAndFillDialogCallback),
+              (override));
 };
 
 }  // namespace
@@ -71,6 +101,31 @@
         std::make_unique<SaveAndFillManagerImpl>(autofill_client_.get());
   }
 
+  void SetUpGetDetailsForCreateCardResponse(
+      PaymentsAutofillClient::PaymentsRpcResult result,
+      bool create_valid_legal_message) {
+    ON_CALL(*mock_network_interface_,
+            GetDetailsForCreateCard(testing::_, testing::_))
+        .WillByDefault([result, create_valid_legal_message](
+                           const auto& /*request_details*/,
+                           base::OnceCallback<void(
+                               PaymentsAutofillClient::PaymentsRpcResult,
+                               const std::u16string&,
+                               std::unique_ptr<base::Value::Dict>,
+                               std::vector<std::pair<int, int>>)> callback) {
+          std::move(callback).Run(
+              result, u"context_token",
+              create_valid_legal_message
+                  ? std::make_unique<base::Value::Dict>(
+                        base::JSONReader::ReadDict(kLegalMessageLines).value())
+                  : std::make_unique<base::Value::Dict>(
+                        base::JSONReader::ReadDict(kInvalidLegalMessageLines)
+                            .value()),
+              {});
+          return RequestId("11223344");
+        });
+  }
+
  protected:
   base::test::TaskEnvironment task_environment_;
   std::unique_ptr<TestAutofillClient> autofill_client_;
@@ -266,4 +321,60 @@
             !details.client_behavior_signals.empty());
 }
 
+// Test that the server dialog is shown when the preflight call succeeds and
+// legal messages are parsed correctly.
+TEST_F(SaveAndFillManagerImplTest,
+       OnDidGetDetailsForCreateCard_Success_OfferUploadSaveAndFill) {
+  save_and_fill_manager_impl_->SetCreditCardUploadEnabledOverrideForTesting(
+      true);
+  SetUpGetDetailsForCreateCardResponse(
+      PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
+      /*create_valid_legal_message=*/true);
+
+  EXPECT_CALL(*mock_network_interface_,
+              GetDetailsForCreateCard(testing::_, testing::_));
+  EXPECT_CALL(*payments_autofill_client_,
+              ShowCreditCardUploadSaveAndFillDialog);
+
+  save_and_fill_manager_impl_->OnDidAcceptCreditCardSaveAndFillSuggestion(
+      fill_card_callback_.Get());
+}
+
+// Test that local Save and Fill is offered as a fallback when legal message
+// parsing fails.
+TEST_F(
+    SaveAndFillManagerImplTest,
+    OnDidGetDetailsForCreateCard_LegalMessageFails_FallbackToLocalSaveAndFill) {
+  save_and_fill_manager_impl_->SetCreditCardUploadEnabledOverrideForTesting(
+      true);
+  SetUpGetDetailsForCreateCardResponse(
+      PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
+      /*create_valid_legal_message=*/false);
+
+  EXPECT_CALL(*mock_network_interface_,
+              GetDetailsForCreateCard(testing::_, testing::_));
+  EXPECT_CALL(*payments_autofill_client_, ShowCreditCardLocalSaveAndFillDialog);
+
+  save_and_fill_manager_impl_->OnDidAcceptCreditCardSaveAndFillSuggestion(
+      fill_card_callback_.Get());
+}
+
+// Test that local Save and Fill is offered as a fallback when the preflight RPC
+// fails.
+TEST_F(SaveAndFillManagerImplTest,
+       OnDidGetDetailsForCreateCard_RpcFailure_FallbackToLocalSaveAndFill) {
+  save_and_fill_manager_impl_->SetCreditCardUploadEnabledOverrideForTesting(
+      true);
+  SetUpGetDetailsForCreateCardResponse(
+      PaymentsAutofillClient::PaymentsRpcResult::kPermanentFailure,
+      /*create_valid_legal_message=*/true);
+
+  EXPECT_CALL(*mock_network_interface_,
+              GetDetailsForCreateCard(testing::_, testing::_));
+  EXPECT_CALL(*payments_autofill_client_, ShowCreditCardLocalSaveAndFillDialog);
+
+  save_and_fill_manager_impl_->OnDidAcceptCreditCardSaveAndFillSuggestion(
+      fill_card_callback_.Get());
+}
+
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager.cc b/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager.cc
index f906a1e5..175476e6 100644
--- a/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager.cc
+++ b/components/autofill/core/browser/single_field_fillers/payments/merchant_promo_code_manager.cc
@@ -49,7 +49,8 @@
   auto on_suggestion_data_returned = base::BindOnce(
       [](base::OnceCallback<void(SuggestionGenerator::ReturnedSuggestions)>
              callback,
-         const FormStructure& form, const AutofillField& autofill_field,
+         const FormFieldData& field, const FormStructure* form,
+         const AutofillField* autofill_field,
          base::WeakPtr<MerchantPromoCodeSuggestionGenerator>
              merchant_promo_code_suggestion_generator,
          std::pair<FillingProduct,
@@ -57,18 +58,18 @@
              suggestion_data) {
         if (merchant_promo_code_suggestion_generator) {
           merchant_promo_code_suggestion_generator->GenerateSuggestions(
-              form, autofill_field, {suggestion_data}, std::move(callback));
+              form->ToFormData(), field, form, autofill_field,
+              {suggestion_data}, std::move(callback));
         }
       },
-      std::move(on_suggestions_generated), std::cref(form_structure),
-      std::cref(autofill_field),
-      merchant_promo_code_suggestion_generator.GetWeakPtr());
+      std::move(on_suggestions_generated), std::cref(field), &form_structure,
+      &autofill_field, merchant_promo_code_suggestion_generator.GetWeakPtr());
 
   // Since the `on_suggestion_data_returned` callback is called synchronously,
   // we can assume that `suggestions_generated` will hold correct value.
   merchant_promo_code_suggestion_generator.FetchSuggestionData(
-      form_structure, autofill_field, client,
-      std::move(on_suggestion_data_returned));
+      form_structure.ToFormData(), field, &form_structure, &autofill_field,
+      client, std::move(on_suggestion_data_returned));
   return suggestions_generated;
 }
 
diff --git a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.cc b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.cc
index 84e217e8d..ead07b69 100644
--- a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.cc
+++ b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.cc
@@ -26,15 +26,17 @@
 
 
 void IbanSuggestionGenerator::FetchSuggestionData(
-    const FormStructure& form,
-    const AutofillField& field,
+    const FormData& form_data,
+    const FormFieldData& field_data,
+    const FormStructure* form,
+    const AutofillField* field,
     const AutofillClient& client,
     base::OnceCallback<
         void(std::pair<FillingProduct,
                        std::vector<SuggestionGenerator::SuggestionData>>)>
         callback) {
   // The field is eligible only if it's focused on an IBAN field.
-  if (field.Type().GetStorableType() != IBAN_VALUE) {
+  if (!field || field->Type().GetStorableType() != IBAN_VALUE) {
     std::move(callback).Run({FillingProduct::kIban, {}});
     return;
   }
@@ -48,7 +50,7 @@
   if (auto* autofill_optimization_guide =
           client.GetAutofillOptimizationGuide()) {
     if (autofill_optimization_guide->ShouldBlockSingleFieldSuggestions(
-            client.GetLastCommittedPrimaryMainFrameOrigin().GetURL(), &field)) {
+            client.GetLastCommittedPrimaryMainFrameOrigin().GetURL(), field)) {
       autofill_metrics::LogIbanSuggestionBlockListStatusMetric(
           autofill_metrics::IbanSuggestionBlockListStatus::kBlocked);
       std::move(callback).Run({FillingProduct::kIban, {}});
@@ -65,7 +67,7 @@
   std::vector<Iban> ibans = client.GetPaymentsAutofillClient()
                                 ->GetPaymentsDataManager()
                                 .GetOrderedIbansToSuggest();
-  FilterIbansToSuggest(field.value(), ibans);
+  FilterIbansToSuggest(field->value(), ibans);
   std::vector<SuggestionData> suggestion_data = base::ToVector(
       std::move(ibans),
       [](Iban& iban) { return SuggestionData(std::move(iban)); });
@@ -73,8 +75,10 @@
 }
 
 void IbanSuggestionGenerator::GenerateSuggestions(
-    const FormStructure& form,
-    const AutofillField& field,
+    const FormData& form_data,
+    const FormFieldData& field_data,
+    const FormStructure* form,
+    const AutofillField* field,
     const std::vector<std::pair<FillingProduct, std::vector<SuggestionData>>>&
         all_suggestion_data,
     base::OnceCallback<void(ReturnedSuggestions)> callback) {
@@ -88,8 +92,8 @@
       });
   // If the input box content equals any of the available IBANs, then
   // assume the IBAN has been filled, and don't show any suggestions.
-  if (!field.value().empty() &&
-      base::Contains(ibans, field.value(), &Iban::value)) {
+  if (!field || (!field->value().empty() &&
+      base::Contains(ibans, field->value(), &Iban::value))) {
     std::move(callback).Run({FillingProduct::kIban, {}});
     return;
   }
@@ -98,8 +102,9 @@
       {FillingProduct::kIban, GetSuggestionsForIbans(ibans)});
 }
 
-void IbanSuggestionGenerator::FilterIbansToSuggest(const std::u16string& field_value,
-                                       std::vector<Iban>& ibans) {
+void IbanSuggestionGenerator::FilterIbansToSuggest(
+    const std::u16string& field_value,
+    std::vector<Iban>& ibans) {
   std::erase_if(ibans, [&](const Iban& iban) {
     if (iban.record_type() == Iban::kLocalIban) {
       return !base::StartsWith(iban.value(), field_value);
diff --git a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.h b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.h
index 23efa27..8486b13 100644
--- a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.h
+++ b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator.h
@@ -15,8 +15,10 @@
   ~IbanSuggestionGenerator() override;
 
   void FetchSuggestionData(
-      const FormStructure& form,
-      const AutofillField& field,
+      const FormData& form_data,
+      const FormFieldData& field_data,
+      const FormStructure* form,
+      const AutofillField* field,
       const AutofillClient& client,
       base::OnceCallback<
           void(std::pair<FillingProduct,
@@ -24,8 +26,10 @@
           callback) override;
 
   void GenerateSuggestions(
-      const FormStructure& form,
-      const AutofillField& field,
+      const FormData& form_data,
+      const FormFieldData& field_data,
+      const FormStructure* form,
+      const AutofillField* field,
       const std::vector<std::pair<FillingProduct, std::vector<SuggestionData>>>&
           all_suggestion_data,
       base::OnceCallback<void(ReturnedSuggestions)> callback) override;
diff --git a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc
index 5cbccb4..cfbeed2 100644
--- a/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/suggestions/payments/iban_suggestion_generator_unittest.cc
@@ -183,20 +183,20 @@
   EXPECT_CALL(suggestion_data_callback,
               Run(testing::Pair(FillingProduct::kIban, testing::SizeIs(4))))
       .WillOnce(testing::SaveArg<0>(&savedCallbackArgument));
-  generator.FetchSuggestionData(form(), field(), client(),
-                                suggestion_data_callback.Get());
+  generator.FetchSuggestionData(form().ToFormData(), field(), &form(), &field(),
+                                client(), suggestion_data_callback.Get());
 
   EXPECT_CALL(suggestions_generated_callback,
               Run(testing::Pair(
                   FillingProduct::kIban,
                   testing::UnorderedElementsAre(
-                    MatchesTextAndSuggestionType(local_iban_suggestion_0),
-                    MatchesTextAndSuggestionType(local_iban_suggestion_1),
-                    MatchesTextAndSuggestionType(server_iban_suggestion_0),
-                    MatchesTextAndSuggestionType(server_iban_suggestion_1),
-                    MatchesTextAndSuggestionType(separator_suggestion),
-                    MatchesTextAndSuggestionType(footer_suggestion)))));
-  generator.GenerateSuggestions(form(), field(),
+                      MatchesTextAndSuggestionType(local_iban_suggestion_0),
+                      MatchesTextAndSuggestionType(local_iban_suggestion_1),
+                      MatchesTextAndSuggestionType(server_iban_suggestion_0),
+                      MatchesTextAndSuggestionType(server_iban_suggestion_1),
+                      MatchesTextAndSuggestionType(separator_suggestion),
+                      MatchesTextAndSuggestionType(footer_suggestion)))));
+  generator.GenerateSuggestions(form().ToFormData(), field(), &form(), &field(),
                                 {savedCallbackArgument},
                                 suggestions_generated_callback.Get());
   task_environment().RunUntilIdle();
diff --git a/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.cc b/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.cc
index 5d4f207..98bc325 100644
--- a/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.cc
+++ b/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.cc
@@ -18,15 +18,18 @@
     default;
 
 void MerchantPromoCodeSuggestionGenerator::FetchSuggestionData(
-    const FormStructure& form,
-    const AutofillField& field,
+    const FormData& form_data,
+    const FormFieldData& field_data,
+    const FormStructure* form,
+    const AutofillField* field,
     const AutofillClient& client,
     base::OnceCallback<
         void(std::pair<FillingProduct,
                        std::vector<SuggestionGenerator::SuggestionData>>)>
         callback) {
   // The field is eligible only if it's focused on a merchant promo code.
-  if (field.Type().GetStorableType() != MERCHANT_PROMO_CODE) {
+  if (!form || !field ||
+      field->Type().GetStorableType() != MERCHANT_PROMO_CODE) {
     std::move(callback).Run({FillingProduct::kMerchantPromoCode, {}});
     return;
   }
@@ -41,12 +44,12 @@
       client.GetPaymentsAutofillClient()
           ->GetPaymentsDataManager()
           .GetActiveAutofillPromoCodeOffersForOrigin(
-              form.main_frame_origin().GetURL());
+              form->main_frame_origin().GetURL());
 
   // If the input box content equals any of the available promo codes, then
   // assume the promo code has been filled, and don't show any suggestions.
   for (const AutofillOfferData* promo_code_offer : promo_code_offers) {
-    if (field.value() == base::ASCIIToUTF16(promo_code_offer->GetPromoCode())) {
+    if (field->value() == base::ASCIIToUTF16(promo_code_offer->GetPromoCode())) {
       std::move(callback).Run({FillingProduct::kMerchantPromoCode, {}});
       return;
     }
@@ -60,8 +63,10 @@
 }
 
 void MerchantPromoCodeSuggestionGenerator::GenerateSuggestions(
-    const FormStructure& form,
-    const AutofillField& field,
+    const FormData& form_data,
+    const FormFieldData& field_data,
+    const FormStructure* form,
+    const AutofillField* field,
     const std::vector<std::pair<FillingProduct, std::vector<SuggestionData>>>&
         all_suggestion_data,
     base::OnceCallback<void(ReturnedSuggestions)> callback) {
diff --git a/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.h b/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.h
index ded88c0..5d006612 100644
--- a/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.h
+++ b/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator.h
@@ -15,8 +15,10 @@
   ~MerchantPromoCodeSuggestionGenerator() override;
 
   void FetchSuggestionData(
-      const FormStructure& form,
-      const AutofillField& field,
+      const FormData& form_data,
+      const FormFieldData& field_data,
+      const FormStructure* form,
+      const AutofillField* field,
       const AutofillClient& client,
       base::OnceCallback<
           void(std::pair<FillingProduct,
@@ -24,8 +26,10 @@
           callback) override;
 
   void GenerateSuggestions(
-      const FormStructure& form,
-      const AutofillField& field,
+      const FormData& form_data,
+      const FormFieldData& field_data,
+      const FormStructure* form,
+      const AutofillField* field,
       const std::vector<std::pair<FillingProduct, std::vector<SuggestionData>>>&
           all_suggestion_data,
       base::OnceCallback<void(ReturnedSuggestions)> callback) override;
diff --git a/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator_unittest.cc
index d29840b..4d28104 100644
--- a/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/suggestions/payments/merchant_promo_code_suggestion_generator_unittest.cc
@@ -100,8 +100,8 @@
               Run(testing::Pair(FillingProduct::kMerchantPromoCode,
                                 testing::ElementsAre(testPromoCodeOfferData))))
       .WillOnce(testing::SaveArg<0>(&savedCallbackArgument));
-  generator.FetchSuggestionData(form(), field(), client(),
-                                suggestion_data_callback.Get());
+  generator.FetchSuggestionData(form().ToFormData(), field(), &form(), &field(),
+                                client(), suggestion_data_callback.Get());
 
   EXPECT_CALL(
       suggestions_generated_callback,
@@ -111,7 +111,8 @@
               Field(&Suggestion::main_text, promo_code_suggestion.main_text),
               Field(&Suggestion::type, SuggestionType::kSeparator),
               Field(&Suggestion::main_text, footer_suggestion.main_text)))));
-  generator.GenerateSuggestions(form(), field(), {savedCallbackArgument},
+  generator.GenerateSuggestions(form().ToFormData(), field(), &form(), &field(),
+                                {savedCallbackArgument},
                                 suggestions_generated_callback.Get());
 }
 
diff --git a/components/autofill/core/browser/suggestions/suggestion_generator.h b/components/autofill/core/browser/suggestions/suggestion_generator.h
index f734de453..3d6a0a0 100644
--- a/components/autofill/core/browser/suggestions/suggestion_generator.h
+++ b/components/autofill/core/browser/suggestions/suggestion_generator.h
@@ -56,9 +56,13 @@
   // top-level documentation of `SuggestionGenerator` for more details).
   // Once the data is obtained, `callback` is called with the `FillingProduct`
   // of which the data is for and the corresponding `SuggestionData`.
+  // `form` and `field` may be null if the `form_data` or `field_data` wasn't
+  // yet parsed.
   virtual void FetchSuggestionData(
-      const FormStructure& form,
-      const AutofillField& field,
+      const FormData& form_data,
+      const FormFieldData& field_data,
+      const FormStructure* form,
+      const AutofillField* field,
       const AutofillClient& client,
       base::OnceCallback<
           void(std::pair<FillingProduct,
@@ -71,9 +75,13 @@
   // Suggestions were triggered on `field` which belongs to `form`. `callback`
   // is called when generation is complete and a list of `Suggestion`
   // objects is passed along with the corresponding `FillingProduct`.
+  // `form` and `field` may be null if the `form_data` or `field_data` wasn't
+  // yet parsed.
   virtual void GenerateSuggestions(
-      const FormStructure& form,
-      const AutofillField& field,
+      const FormData& form_data,
+      const FormFieldData& field_data,
+      const FormStructure* form,
+      const AutofillField* field,
       const std::vector<std::pair<FillingProduct, std::vector<SuggestionData>>>&
           all_suggestion_data,
       base::OnceCallback<void(ReturnedSuggestions)> callback) = 0;
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc
index 51bd17a..2aea6f62 100644
--- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc
+++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.cc
@@ -21,7 +21,7 @@
 SaveAndFillDialogControllerImpl::SaveAndFillDialogControllerImpl() = default;
 SaveAndFillDialogControllerImpl::~SaveAndFillDialogControllerImpl() = default;
 
-void SaveAndFillDialogControllerImpl::ShowDialog(
+void SaveAndFillDialogControllerImpl::ShowLocalDialog(
     base::OnceCallback<std::unique_ptr<SaveAndFillDialogView>()>
         create_and_show_view_callback,
     payments::PaymentsAutofillClient::CardSaveAndFillDialogCallback
@@ -32,6 +32,20 @@
   CHECK(dialog_view_);
 }
 
+void SaveAndFillDialogControllerImpl::ShowUploadDialog(
+    const LegalMessageLines& legal_message_lines,
+    base::OnceCallback<std::unique_ptr<SaveAndFillDialogView>()>
+        create_and_show_view_callback,
+    payments::PaymentsAutofillClient::CardSaveAndFillDialogCallback
+        card_save_and_fill_dialog_callback) {
+  dialog_view_ = std::move(create_and_show_view_callback).Run();
+  card_save_and_fill_dialog_callback_ =
+      std::move(card_save_and_fill_dialog_callback);
+  legal_message_lines_ = legal_message_lines;
+  is_upload_save_and_fill_ = true;
+  CHECK(dialog_view_);
+}
+
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 std::u16string SaveAndFillDialogControllerImpl::GetWindowTitle() const {
   return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_AND_FILL_DIALOG_TITLE);
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h
index 3707fcd..f6acadb 100644
--- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h
+++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl.h
@@ -25,7 +25,14 @@
       const SaveAndFillDialogControllerImpl&) = delete;
   ~SaveAndFillDialogControllerImpl() override;
 
-  void ShowDialog(
+  void ShowLocalDialog(
+      base::OnceCallback<std::unique_ptr<SaveAndFillDialogView>()>
+          create_and_show_view_callback,
+      payments::PaymentsAutofillClient::CardSaveAndFillDialogCallback
+          card_save_and_fill_dialog_callback);
+
+  void ShowUploadDialog(
+      const LegalMessageLines& legal_message_lines,
       base::OnceCallback<std::unique_ptr<SaveAndFillDialogView>()>
           create_and_show_view_callback,
       payments::PaymentsAutofillClient::CardSaveAndFillDialogCallback
@@ -73,6 +80,8 @@
   // shown.
   bool is_upload_save_and_fill_ = false;
 
+  LegalMessageLines legal_message_lines_;
+
   payments::PaymentsAutofillClient::CardSaveAndFillDialogCallback
       card_save_and_fill_dialog_callback_;
 
diff --git a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl_unittest.cc b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl_unittest.cc
index 34ec1cd5..2c78b2c 100644
--- a/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl_unittest.cc
+++ b/components/autofill/core/browser/ui/payments/save_and_fill_dialog_controller_impl_unittest.cc
@@ -30,8 +30,8 @@
     EXPECT_CALL(create_and_show_view_callback, Run())
         .WillOnce(testing::Return(std::make_unique<SaveAndFillDialogView>()));
 
-    controller_->ShowDialog(create_and_show_view_callback.Get(),
-                            card_save_and_fill_dialog_callback_.Get());
+    controller_->ShowLocalDialog(create_and_show_view_callback.Get(),
+                                 card_save_and_fill_dialog_callback_.Get());
   }
 
   SaveAndFillDialogControllerImpl* controller() const {
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 2733a0c..9ac29bb 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -467,7 +467,7 @@
 // TODO(crbug.com/395855125): Remove when launched.
 BASE_FEATURE(kAutofillRelaxAddressImport,
              "AutofillRelaxAddressImport",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Replaces blink::WebFormElementObserver usage in FormTracker by updated logic
 // for tracking the disappearance of forms as well as other submission
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc
index b377752..05dd22b 100644
--- a/components/autofill/core/common/autofill_payments_features.cc
+++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -73,7 +73,7 @@
 // Payments Autofill UI.
 BASE_FEATURE(kAutofillEnableCardBenefitsForAmericanExpress,
              "AutofillEnableCardBenefitsForAmericanExpress",
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+#if BUILDFLAG(IS_IOS)
              base::FEATURE_DISABLED_BY_DEFAULT);
 #else
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index b421516..09812efaae 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -37,7 +37,22 @@
     <message name="IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY" desc="Text in a dialog to confirm that the user wants to delete an address from Autofill.">
       Remove address from Chromium?
     </message>
-  </if>
+    </if>
+    <message name="IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_TITLE" desc="Title in a dialog to confirm that the user wants to delete their Home address from Autofill.">
+    Remove home address from Chrome autofill?
+    </message>
+    <message name="IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_BODY" desc="Text in a dialog to confirm that the user wants to delete their Home address from Autofill.">
+    Your home address can help you get things done across Google services, like more relevant Search results and directions in Google Maps. You can edit or delete your address <ph name="BEGIN_LINK">&lt;link&gt;</ph>in your Google Account <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph><ph name="END_LINK">&lt;/link&gt;</ph>.
+    </message>
+    <message name="IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_TITLE" desc="Title in a dialog to confirm that the user wants to delete their Work address from Autofill.">
+    Remove work address from Chrome autofill?
+    </message>
+      <message name="IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_BODY" desc="Title in a dialog to confirm that the user wants to delete their Work address from Autofill.">
+    Your work address can help you get things done across Google services, like more relevant Search results and directions in Google Maps. You can edit or delete your address <ph name="BEGIN_LINK">&lt;link&gt;</ph>in your Google Account <ph name="ACCOUNT">$1<ex>alexpark@gmail.com</ex></ph><ph name="END_LINK">&lt;/link&gt;</ph>.
+  </message>
+  <message name="IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON" desc="Text in a remove button for Autofill suggestion.">
+    Remove
+  </message>
   <message name="IDS_AUTOFILL_DELETE_SUGGESTION_BUTTON" desc="Text in a delete button for Autofill suggestion.">
     Delete
   </message>
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_BODY.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_BODY.png.sha1
new file mode 100644
index 0000000..558371b1
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_BODY.png.sha1
@@ -0,0 +1 @@
+53a5f737e6c6ee4561fed697111bfaaf3643d87b
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_TITLE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_TITLE.png.sha1
new file mode 100644
index 0000000..558371b1
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_HOME_PROFILE_SUGGESTION_CONFIRMATION_TITLE.png.sha1
@@ -0,0 +1 @@
+53a5f737e6c6ee4561fed697111bfaaf3643d87b
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON.png.sha1
new file mode 100644
index 0000000..558371b1
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_SUGGESTION_BUTTON.png.sha1
@@ -0,0 +1 @@
+53a5f737e6c6ee4561fed697111bfaaf3643d87b
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_BODY.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_BODY.png.sha1
new file mode 100644
index 0000000..562858f
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_BODY.png.sha1
@@ -0,0 +1 @@
+90f61e5aeb17e25f3894586f31c99bf97a6dc746
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_TITLE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_TITLE.png.sha1
new file mode 100644
index 0000000..562858f
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_REMOVE_WORK_PROFILE_SUGGESTION_CONFIRMATION_TITLE.png.sha1
@@ -0,0 +1 @@
+90f61e5aeb17e25f3894586f31c99bf97a6dc746
\ No newline at end of file
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
index 8209b12..8f25c13 100644
--- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
+++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaSessionHelper.java
@@ -515,7 +515,7 @@
      * Updates the best favicon if the given icon is better and the favicon is shown in
      * notification.
      */
-    public void updateFavicon(Bitmap icon) {
+    public void updateFavicon(@Nullable Bitmap icon) {
         if (icon == null) return;
 
         mMaybeHasFavicon = true;
diff --git a/components/browser_ui/site_settings/android/BUILD.gn b/components/browser_ui/site_settings/android/BUILD.gn
index 04d3c024..5fb8b5c 100644
--- a/components/browser_ui/site_settings/android/BUILD.gn
+++ b/components/browser_ui/site_settings/android/BUILD.gn
@@ -6,7 +6,10 @@
 import("//third_party/jni_zero/jni_zero.gni")
 
 generate_jni("site_settings_jni_headers") {
-  sources = [ "java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java" ]
+  sources = [
+    "java/src/org/chromium/components/browser_ui/site_settings/GeolocationSetting.java",
+    "java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java",
+  ]
 }
 
 source_set("android") {
@@ -72,6 +75,7 @@
     "java/src/org/chromium/components/browser_ui/site_settings/DesktopSiteMetrics.java",
     "java/src/org/chromium/components/browser_ui/site_settings/FileEditingInfo.java",
     "java/src/org/chromium/components/browser_ui/site_settings/ForwardingManagedPreferenceDelegate.java",
+    "java/src/org/chromium/components/browser_ui/site_settings/GeolocationSetting.java",
     "java/src/org/chromium/components/browser_ui/site_settings/GroupedWebsitesSettings.java",
     "java/src/org/chromium/components/browser_ui/site_settings/JavascriptOptimizerCategory.java",
     "java/src/org/chromium/components/browser_ui/site_settings/LocalStorageInfo.java",
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GeolocationSetting.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GeolocationSetting.java
new file mode 100644
index 0000000..10666ca
--- /dev/null
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/GeolocationSetting.java
@@ -0,0 +1,48 @@
+// 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.components.browser_ui.site_settings;
+
+import androidx.annotation.NonNull;
+
+import org.jni_zero.CalledByNative;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.components.content_settings.ContentSettingValues;
+
+import java.util.Objects;
+
+@NullMarked
+public final class GeolocationSetting {
+    public final @ContentSettingValues int mApproximate;
+    public final @ContentSettingValues int mPrecise;
+
+    @CalledByNative
+    public GeolocationSetting(
+            @ContentSettingValues int approximate, @ContentSettingValues int precise) {
+        mApproximate = approximate;
+        mPrecise = precise;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        return o instanceof GeolocationSetting that
+                && mApproximate == that.mApproximate
+                && mPrecise == that.mPrecise;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mApproximate, mPrecise);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "GeolocationSetting{" + mApproximate + ", " + mPrecise + "}";
+    }
+}
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/PermissionInfo.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/PermissionInfo.java
index e506fa24..d3881bac 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/PermissionInfo.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/PermissionInfo.java
@@ -14,7 +14,6 @@
 import org.chromium.content_public.browser.BrowserContextHandle;
 
 import java.io.Serializable;
-import java.util.Objects;
 
 /** Permission information for a given origin. */
 @NullMarked
@@ -24,7 +23,6 @@
     private final String mOrigin;
     private final @ContentSettingsType.EnumType int mContentSettingsType;
     private final @SessionModel.EnumType int mSessionModel;
-    private static @Nullable GeolocationSetting sMockSetting;
 
     public PermissionInfo(
             @ContentSettingsType.EnumType int type,
@@ -87,32 +85,6 @@
                 browserContextHandle, mContentSettingsType, mOrigin, mEmbedder);
     }
 
-    public static final class GeolocationSetting {
-        public GeolocationSetting(
-                @ContentSettingValues int approximate, @ContentSettingValues int precise) {
-            mApproximate = approximate;
-            mPrecise = precise;
-        }
-
-        final @ContentSettingValues int mApproximate;
-        final @ContentSettingValues int mPrecise;
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            return o instanceof GeolocationSetting that
-                    && mApproximate == that.mApproximate
-                    && mPrecise == that.mPrecise;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mApproximate, mPrecise);
-        }
-    }
-
     /** Sets the native ContentSetting value for this origin. */
     public void setContentSetting(
             BrowserContextHandle browserContextHandle, @ContentSettingValues int value) {
@@ -128,36 +100,42 @@
     /** Returns the Geolocation permission value for this origin. */
     public @Nullable GeolocationSetting getGeolocationSetting(
             BrowserContextHandle browserContextHandle) {
-        assert mContentSettingsType == ContentSettingsType.GEOLOCATION;
+        assert mContentSettingsType == ContentSettingsType.GEOLOCATION_WITH_OPTIONS;
         assert PermissionsAndroidFeatureMap.isEnabled(
                 PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION);
-        // Return fake precise permission for maps.google.com and approximate for permission.site
-        // until we can set create real approximate permissions.
+
+        GeolocationSetting setting =
+                WebsitePreferenceBridgeJni.get()
+                        .getGeolocationSettingForOrigin(
+                                browserContextHandle,
+                                mContentSettingsType,
+                                mOrigin,
+                                getEmbedderSafe());
+
+        // Return fake approximate permission for permission.site until we can set create real
+        // approximate permissions.
         if (PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_SAMPLE_DATA.getValue()) {
-            if (mOrigin.equals("https://permission.site")) {
-                if (sMockSetting == null) {
-                    sMockSetting =
-                            new GeolocationSetting(
-                                    ContentSettingValues.ALLOW, ContentSettingValues.BLOCK);
-                }
-                return sMockSetting;
+            if (mOrigin.equals("https://permission.site")
+                    && setting.mPrecise == ContentSettingValues.ASK
+                    && setting.mApproximate == ContentSettingValues.ASK) {
+                return new GeolocationSetting(
+                        ContentSettingValues.ALLOW, ContentSettingValues.BLOCK);
             }
         }
-        // TODO(crbug.com/418938557) Get value from content settings. We probably only want a
-        // base::Value API for get/set of complex permissions to avoid adding bridge methods for
-        // every such permission.
-        return null;
+        return setting;
     }
 
     /** Set the Geolocation permission value for this origin. */
     public void setGeolocationSetting(
             BrowserContextHandle browserContextHandle, GeolocationSetting setting) {
-        assert mContentSettingsType == ContentSettingsType.GEOLOCATION;
-        if (PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_SAMPLE_DATA.getValue()) {
-            if (mOrigin.equals("https://permission.site")) {
-                sMockSetting = setting;
-            }
-        }
-        // TODO(crbug.com/418938557) Set new value in content settings.
+        assert mContentSettingsType == ContentSettingsType.GEOLOCATION_WITH_OPTIONS;
+        WebsitePreferenceBridgeJni.get()
+                .setGeolocationSettingForOrigin(
+                        browserContextHandle,
+                        mContentSettingsType,
+                        mOrigin,
+                        getEmbedderSafe(),
+                        setting.mApproximate,
+                        setting.mPrecise);
     }
 }
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java
index b927c3be..355cb51 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePermissionsFetcher.java
@@ -18,6 +18,8 @@
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.content_settings.SessionModel;
+import org.chromium.components.permissions.PermissionsAndroidFeatureList;
+import org.chromium.components.permissions.PermissionsAndroidFeatureMap;
 import org.chromium.content_public.browser.BrowserContextHandle;
 import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.ContentFeatureMap;
@@ -115,9 +117,16 @@
             case ContentSettingsType.SERIAL_GUARD:
             case ContentSettingsType.USB_GUARD:
                 return WebsitePermissionsType.CHOSEN_OBJECT_INFO;
+            case ContentSettingsType.GEOLOCATION_WITH_OPTIONS:
+                if (PermissionsAndroidFeatureMap.isEnabled(
+                        PermissionsAndroidFeatureList.APPROXIMATE_GEOLOCATION_PERMISSION)) {
+                    return WebsitePermissionsType.PERMISSION_INFO;
+                }
+                break;
             default:
                 return null;
         }
+        return null;
     }
 
     /**
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java
index 66303ad1..19b0fcd 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/WebsitePreferenceBridge.java
@@ -573,6 +573,20 @@
                 String embedder,
                 @ContentSettingValues int value);
 
+        GeolocationSetting getGeolocationSettingForOrigin(
+                BrowserContextHandle browserContextHandle,
+                @ContentSettingsType.EnumType int contentSettingsType,
+                String origin,
+                String embedder);
+
+        void setGeolocationSettingForOrigin(
+                BrowserContextHandle browserContextHandle,
+                @ContentSettingsType.EnumType int contentSettingsType,
+                String origin,
+                String embedder,
+                @ContentSettingValues int approximate,
+                @ContentSettingValues int precise);
+
         void setEphemeralGrantForTesting( // IN-TEST
                 BrowserContextHandle browserContextHandle,
                 @ContentSettingsType.EnumType int contentSettingsType,
diff --git a/components/browser_ui/site_settings/android/website_preference_bridge.cc b/components/browser_ui/site_settings/android/website_preference_bridge.cc
index 1fbceac..90f3ecf 100644
--- a/components/browser_ui/site_settings/android/website_preference_bridge.cc
+++ b/components/browser_ui/site_settings/android/website_preference_bridge.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <set>
 #include <string>
+#include <variant>
 #include <vector>
 
 #include "base/android/callback_android.h"
@@ -25,6 +26,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
+#include "components/browser_ui/site_settings/android/site_settings_jni_headers/GeolocationSetting_jni.h"
 #include "components/browser_ui/site_settings/android/storage_info_fetcher.h"
 #include "components/browser_ui/site_settings/android/website_preference_bridge_util.h"
 #include "components/browsing_data/content/cookie_helper.h"
@@ -339,6 +341,30 @@
   return provider >= content_settings::ProviderType::kPrefProvider;
 }
 
+ContentSetting ToContentSetting(PermissionOption option) {
+  switch (option) {
+    case PermissionOption::kAllowed:
+      return CONTENT_SETTING_ALLOW;
+    case PermissionOption::kDenied:
+      return CONTENT_SETTING_BLOCK;
+    case PermissionOption::kAsk:
+      return CONTENT_SETTING_ASK;
+  }
+}
+
+PermissionOption ToPermissionOption(ContentSetting setting) {
+  switch (setting) {
+    case CONTENT_SETTING_ALLOW:
+      return PermissionOption::kAllowed;
+    case CONTENT_SETTING_BLOCK:
+      return PermissionOption::kDenied;
+    case CONTENT_SETTING_ASK:
+      return PermissionOption::kAsk;
+    default:
+      NOTREACHED();
+  }
+}
+
 }  // anonymous namespace
 
 static jboolean JNI_WebsitePreferenceBridge_IsNotificationEmbargoedForOrigin(
@@ -442,6 +468,58 @@
   }
 }
 
+static ScopedJavaLocalRef<jobject>
+JNI_WebsitePreferenceBridge_GetGeolocationSettingForOrigin(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jbrowser_context_handle,
+    jint content_settings_type,
+    const JavaParamRef<jstring>& origin,
+    const JavaParamRef<jstring>& embedder) {
+  ContentSettingsType type =
+      static_cast<ContentSettingsType>(content_settings_type);
+  GURL origin_url(ConvertJavaStringToUTF8(env, origin));
+  GURL embedder_url =
+      embedder ? GURL(ConvertJavaStringToUTF8(env, embedder)) : GURL();
+
+  BrowserContext* browser_context = unwrap(jbrowser_context_handle);
+
+  auto setting = GetHostContentSettingsMap(browser_context)
+                     ->GetPermissionSetting(origin_url, embedder_url, type);
+
+  DCHECK(std::holds_alternative<GeolocationSetting>(setting))
+      << content_settings_type << " " << setting;
+
+  auto& geo_setting = std::get<GeolocationSetting>(setting);
+
+  return Java_GeolocationSetting_Constructor(
+      env, ToContentSetting(geo_setting.approximate),
+      ToContentSetting(geo_setting.precise));
+}
+
+static void JNI_WebsitePreferenceBridge_SetGeolocationSettingForOrigin(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jbrowser_context_handle,
+    jint content_settings_type,
+    const JavaParamRef<jstring>& origin,
+    const JavaParamRef<jstring>& embedder,
+    jint approximate,
+    jint precise) {
+  GURL origin_url(ConvertJavaStringToUTF8(env, origin));
+  GURL embedder_url =
+      embedder ? GURL(ConvertJavaStringToUTF8(env, embedder)) : GURL();
+
+  BrowserContext* browser_context = unwrap(jbrowser_context_handle);
+
+  GeolocationSetting setting = {
+      ToPermissionOption(static_cast<ContentSetting>(approximate)),
+      ToPermissionOption(static_cast<ContentSetting>(precise))};
+
+  GetHostContentSettingsMap(browser_context)
+      ->SetPermissionSettingDefaultScope(
+          origin_url, embedder_url,
+          static_cast<ContentSettingsType>(content_settings_type), setting);
+}
+
 static void JNI_WebsitePreferenceBridge_SetEphemeralGrantForTesting(  // IN-TEST
     JNIEnv* env,
     const JavaParamRef<jobject>& jbrowser_context_handle,
diff --git a/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml b/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml
index 234e602..893f5a4 100644
--- a/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml
+++ b/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml
@@ -15,8 +15,8 @@
 
     <FrameLayout
         android:id="@+id/rich_radio_button_icon_container"
-        android:layout_width="@dimen/rich_radio_button_icon_container_size"
-        android:layout_height="@dimen/rich_radio_button_icon_container_size"
+        android:layout_width="@dimen/rich_radio_button_horizontal_icon_container_size"
+        android:layout_height="@dimen/rich_radio_button_horizontal_icon_container_size"
         android:background="@drawable/rich_radio_button_background"
         android:gravity="center"
         android:clipToOutline="true"
@@ -32,7 +32,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:layout_gravity="center"
-                android:scaleType="centerInside"
+                android:scaleType="centerCrop"
                 android:visibility="gone" />
     </FrameLayout>
 
@@ -74,6 +74,7 @@
         android:clickable="false"
         android:focusable="false"
         android:button="@null"
+        android:layout_marginEnd="@dimen/rich_radio_button_radio_button_margin_end"
         android:drawableEnd="@drawable/rich_radio_button_selector"
         android:drawableTint="?attr/colorPrimary"
         app:layout_constraintTop_toTopOf="parent"
diff --git a/components/browser_ui/widget/android/java/res/values/dimens.xml b/components/browser_ui/widget/android/java/res/values/dimens.xml
index 0ac6e1f..0c2fdd11 100644
--- a/components/browser_ui/widget/android/java/res/values/dimens.xml
+++ b/components/browser_ui/widget/android/java/res/values/dimens.xml
@@ -238,16 +238,24 @@
     <dimen name="popup_menu_shadow_length">6dp</dimen>
 
     <!-- Rich Radio Button dimens -->
-    <dimen name="rich_radio_button_default_padding">16dp</dimen>
+    <dimen name="rich_radio_button_default_padding">6dp</dimen>
+    <dimen name="rich_radio_button_without_icon_vertical_padding">16dp</dimen>
 
-    <dimen name="rich_radio_button_icon_container_size">80dp</dimen>
+    <dimen name="rich_radio_button_title_margin">16dp</dimen>
+
+    <dimen name="rich_radio_button_horizontal_icon_container_size">80dp</dimen>
+    <dimen name="rich_radio_button_vertical_icon_container_size">120dp</dimen>
+    <dimen name="rich_radio_button_vertical_icon_container_margin_top">14dp</dimen>
 
     <dimen name="rich_radio_button_vertical_margin_bottom">16dp</dimen>
 
     <dimen name="rich_radio_button_icon_margin_end">8dp</dimen>
+    <dimen name="rich_radio_button_radio_button_margin_end">10dp</dimen>
     <dimen name="rich_radio_button_radio_button_margin_start">16dp</dimen>
 
     <dimen name="rich_radio_button_description_margin_top">4dp</dimen>
 
-    <dimen name="rich_radio_button_list_spacing">8dp</dimen>
+    <dimen name="rich_radio_button_list_horizontal_spacing">12dp</dimen>
+    <dimen name="rich_radio_button_list_vertical_spacing">8dp</dimen>
+
 </resources>
diff --git a/components/browser_ui/widget/android/java/res/xml/rich_radio_button_horizontal_constraints.xml b/components/browser_ui/widget/android/java/res/xml/rich_radio_button_horizontal_constraints.xml
index 4d93ff5..73d9a38 100644
--- a/components/browser_ui/widget/android/java/res/xml/rich_radio_button_horizontal_constraints.xml
+++ b/components/browser_ui/widget/android/java/res/xml/rich_radio_button_horizontal_constraints.xml
@@ -10,8 +10,8 @@
 
     <Constraint
         android:id="@+id/rich_radio_button_icon_container"
-        android:layout_width="@dimen/rich_radio_button_icon_container_size"
-        android:layout_height="@dimen/rich_radio_button_icon_container_size"
+        android:layout_width="@dimen/rich_radio_button_horizontal_icon_container_size"
+        android:layout_height="@dimen/rich_radio_button_horizontal_icon_container_size"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
diff --git a/components/browser_ui/widget/android/java/res/xml/rich_radio_button_vertical_constraints.xml b/components/browser_ui/widget/android/java/res/xml/rich_radio_button_vertical_constraints.xml
index 66a47bb..50ca968 100644
--- a/components/browser_ui/widget/android/java/res/xml/rich_radio_button_vertical_constraints.xml
+++ b/components/browser_ui/widget/android/java/res/xml/rich_radio_button_vertical_constraints.xml
@@ -10,14 +10,14 @@
 
     <Constraint
         android:id="@+id/rich_radio_button_icon_container"
-        android:layout_width="@dimen/rich_radio_button_icon_container_size"
-        android:layout_height="@dimen/rich_radio_button_icon_container_size"
+        android:layout_width="@dimen/rich_radio_button_vertical_icon_container_size"
+        android:layout_height="@dimen/rich_radio_button_vertical_icon_container_size"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/rich_radio_button_text_container"
         app:layout_constraintVertical_chainStyle="packed"
-        android:layout_marginTop="0dp"
+        android:layout_marginTop="@dimen/rich_radio_button_vertical_icon_container_margin_top"
         android:layout_marginBottom="@dimen/rich_radio_button_vertical_margin_bottom" />
 
       <Constraint
@@ -40,6 +40,6 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         android:layout_marginTop="0dp"
-        android:layout_marginBottom="0dp" />
+        android:layout_marginBottom="10dp" />
 
 </androidx.constraintlayout.widget.ConstraintSet>
\ No newline at end of file
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java
index 6a499ae..6337c089 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java
@@ -9,8 +9,10 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.Checkable;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import android.widget.RadioButton;
 import android.widget.TextView;
 
@@ -49,6 +51,14 @@
     private boolean mIsChecked;
     private boolean mIsVerticalLayout;
 
+    private int mDefaultRootLayoutPaddingStart;
+    private int mDefaultRootLayoutPaddingTop;
+    private int mDefaultRootLayoutPaddingEnd;
+    private int mDefaultRootLayoutPaddingBottom;
+
+    private ViewGroup.MarginLayoutParams mDefaultTitleLayoutParams;
+    private ViewGroup.MarginLayoutParams mDefaultRadioButtonLayoutParams;
+
     public RichRadioButton(@NonNull Context context) {
         super(context);
         init(context);
@@ -94,6 +104,19 @@
                         info.setClassName(RadioButton.class.getName());
                     }
                 });
+
+        mDefaultRootLayoutPaddingStart = mRootItemLayout.getPaddingStart();
+        mDefaultRootLayoutPaddingTop = mRootItemLayout.getPaddingTop();
+        mDefaultRootLayoutPaddingEnd = mRootItemLayout.getPaddingEnd();
+        mDefaultRootLayoutPaddingBottom = mRootItemLayout.getPaddingBottom();
+
+        mDefaultTitleLayoutParams =
+                new LinearLayout.LayoutParams(
+                        (LinearLayout.LayoutParams) mItemTitle.getLayoutParams());
+
+        mDefaultRadioButtonLayoutParams =
+                new ConstraintLayout.LayoutParams(
+                        (ConstraintLayout.LayoutParams) mItemRadioButton.getLayoutParams());
     }
 
     /**
@@ -114,9 +137,11 @@
             mItemIcon.setImageResource(iconResId);
             mItemIcon.setVisibility(VISIBLE);
             mIconContainer.setVisibility(VISIBLE);
+            resetLayoutWithIcon();
         } else {
             mItemIcon.setVisibility(GONE);
             mIconContainer.setVisibility(GONE);
+            adjustLayoutWithoutIcon();
         }
         mItemTitle.setText(title);
         if (description != null && !description.isEmpty()) {
@@ -128,6 +153,52 @@
         setOrientation(isInternalVertical);
     }
 
+    private void adjustLayoutWithoutIcon() {
+        int layoutVerticalPaddingPx =
+                getContext()
+                        .getResources()
+                        .getDimensionPixelSize(
+                                R.dimen.rich_radio_button_without_icon_vertical_padding);
+        mRootItemLayout.setPaddingRelative(
+                0,
+                layoutVerticalPaddingPx,
+                mRootItemLayout.getPaddingEnd(),
+                layoutVerticalPaddingPx);
+
+        int titleMarginPx =
+                getContext()
+                        .getResources()
+                        .getDimensionPixelSize(R.dimen.rich_radio_button_title_margin);
+
+        LinearLayout.LayoutParams currentTitleParams =
+                (LinearLayout.LayoutParams) mItemTitle.getLayoutParams();
+        LinearLayout.LayoutParams newTitleParams =
+                new LinearLayout.LayoutParams(currentTitleParams);
+        newTitleParams.setMargins(titleMarginPx, titleMarginPx, 0, titleMarginPx);
+        mItemTitle.setLayoutParams(newTitleParams);
+        int radioButtonMarginPx =
+                getContext()
+                        .getResources()
+                        .getDimensionPixelSize(R.dimen.rich_radio_button_radio_button_margin_end);
+        ConstraintLayout.LayoutParams currentRadioButtonParams =
+                (ConstraintLayout.LayoutParams) mItemRadioButton.getLayoutParams();
+        ConstraintLayout.LayoutParams newRadioButtonParams =
+                new ConstraintLayout.LayoutParams(currentRadioButtonParams);
+        newRadioButtonParams.setMarginEnd(radioButtonMarginPx);
+        mItemRadioButton.setLayoutParams(newRadioButtonParams);
+    }
+
+    private void resetLayoutWithIcon() {
+        mRootItemLayout.setPaddingRelative(
+                mDefaultRootLayoutPaddingStart,
+                mDefaultRootLayoutPaddingTop,
+                mDefaultRootLayoutPaddingEnd,
+                mDefaultRootLayoutPaddingBottom);
+
+        mItemTitle.setLayoutParams(mDefaultTitleLayoutParams);
+        mItemRadioButton.setLayoutParams(mDefaultRadioButtonLayoutParams);
+    }
+
     /**
      * Sets the orientation of the item's internal layout.
      *
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonList.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonList.java
index 046fda1..a3be0b5 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonList.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonList.java
@@ -80,21 +80,28 @@
         mCurrentLayoutMode = layoutMode;
 
         RecyclerView.LayoutManager layoutManager;
-        int spacingPx =
-                getContext()
-                        .getResources()
-                        .getDimensionPixelSize(R.dimen.rich_radio_button_list_spacing);
 
         if (layoutMode == LayoutMode.VERTICAL_SINGLE_COLUMN) {
+            int verticalSpacingPx =
+                    getContext()
+                            .getResources()
+                            .getDimensionPixelSize(R.dimen.rich_radio_button_list_vertical_spacing);
             layoutManager =
                     new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
             clearItemDecorations();
-            mRecyclerView.addItemDecoration(new SimpleItemDecoration(spacingPx, 0));
+            mRecyclerView.addItemDecoration(new SimpleItemDecoration(verticalSpacingPx, 0));
             mRecyclerView.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
         } else {
+            int horizontalSpacingPx =
+                    getContext()
+                            .getResources()
+                            .getDimensionPixelSize(
+                                    R.dimen.rich_radio_button_list_horizontal_spacing);
+
             layoutManager = new GridLayoutManager(getContext(), /* spanCount= */ 2);
             clearItemDecorations();
-            mRecyclerView.addItemDecoration(new SimpleItemDecoration(spacingPx, spacingPx));
+            mRecyclerView.addItemDecoration(
+                    new SimpleItemDecoration(horizontalSpacingPx, horizontalSpacingPx));
             mRecyclerView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
         }
         mRecyclerView.setLayoutManager(layoutManager);
@@ -129,7 +136,10 @@
         }
     }
 
-    /** ItemDecoration for spacing between items. */
+    /**
+     * ItemDecoration for spacing between items. GridLayouts have a built-in "space-between"
+     * spacing.
+     */
     private static class SimpleItemDecoration extends RecyclerView.ItemDecoration {
         private final int mVerticalSpaceHeightPx;
         private final int mHorizontalSpaceWidthPx;
@@ -154,6 +164,16 @@
             int spanCount = 1;
             if (parent.getLayoutManager() instanceof GridLayoutManager) {
                 spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
+                int column = position % spanCount;
+                outRect.left = column * mHorizontalSpaceWidthPx / spanCount;
+                outRect.right =
+                        mHorizontalSpaceWidthPx
+                                - (column + 1) * mHorizontalSpaceWidthPx / spanCount;
+
+                if (position < itemCount - spanCount) {
+                    outRect.bottom = mVerticalSpaceHeightPx;
+                }
+                return;
             }
 
             if (position < itemCount - spanCount) {
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java
index 4b8e0ed1..27ef61c 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java
@@ -8,6 +8,7 @@
 import android.graphics.Color;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
 import androidx.test.filters.SmallTest;
@@ -52,9 +53,10 @@
 
     private static Activity sActivity;
 
-    private static final int REVISION = 1;
+    private static final int REVISION = 2;
     private static final String REVISION_DESCRIPTION =
-            "Initial render test for RichRadioButton covering various states and orientations.";
+            "Render test for RichRadioButton covering various states and orientations, with"
+                    + " improved layout";
 
     @Rule
     public RenderTestRule mRenderTestRule =
@@ -195,4 +197,139 @@
                 });
         mRenderTestRule.render(mRichRbVerticalFullUnchecked, "rich_rb_vertical_full_unchecked");
     }
+
+    @Test
+    @SmallTest
+    @Feature({"RichRadioButton"})
+    public void testLayoutParamsPreservedAfterMultipleSetItemDataCalls() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    // Get initial layout params for title and radio button.
+                    ViewGroup.MarginLayoutParams initialTitleParams =
+                            (ViewGroup.MarginLayoutParams)
+                                    mRichRbHorizontalFullUnchecked
+                                            .findViewById(R.id.rich_radio_button_title)
+                                            .getLayoutParams();
+                    ViewGroup.MarginLayoutParams initialRadioButtonParams =
+                            (ViewGroup.MarginLayoutParams)
+                                    mRichRbHorizontalFullUnchecked
+                                            .findViewById(R.id.rich_radio_button_radio_button)
+                                            .getLayoutParams();
+
+                    // Get initial padding for the root layout.
+                    int initialRootPaddingStart = mRichRbHorizontalFullUnchecked.getPaddingStart();
+                    int initialRootPaddingTop = mRichRbHorizontalFullUnchecked.getPaddingTop();
+                    int initialRootPaddingEnd = mRichRbHorizontalFullUnchecked.getPaddingEnd();
+                    int initialRootPaddingBottom =
+                            mRichRbHorizontalFullUnchecked.getPaddingBottom();
+
+                    // Set with icon, then without, then with again.
+                    mRichRbHorizontalFullUnchecked.setItemData(
+                            R.drawable.test_location_precise, "Title A", "Description A", false);
+
+                    mRichRbHorizontalFullUnchecked.setItemData(
+                            0, // No icon
+                            "Title B",
+                            "Description B",
+                            false);
+
+                    mRichRbHorizontalFullUnchecked.setItemData(
+                            R.drawable.test_location_precise, "Title C", "Description C", false);
+
+                    // Assert that the layout params for the root layout , title and radio button
+                    // are the same as their initial values.
+                    ViewGroup.MarginLayoutParams finalTitleParams =
+                            (ViewGroup.MarginLayoutParams)
+                                    mRichRbHorizontalFullUnchecked
+                                            .findViewById(R.id.rich_radio_button_title)
+                                            .getLayoutParams();
+                    ViewGroup.MarginLayoutParams finalRadioButtonParams =
+                            (ViewGroup.MarginLayoutParams)
+                                    mRichRbHorizontalFullUnchecked
+                                            .findViewById(R.id.rich_radio_button_radio_button)
+                                            .getLayoutParams();
+
+                    Assert.assertNotSame(
+                            "Initial and final title LayoutParams should NOT be the same instance",
+                            initialTitleParams,
+                            finalTitleParams);
+
+                    Assert.assertNotSame(
+                            "Initial and final radio button LayoutParams should NOT be the same"
+                                    + " instance",
+                            initialRadioButtonParams,
+                            finalRadioButtonParams);
+
+                    // Check title margins.
+                    Assert.assertEquals(
+                            "Title left margin changed unexpectedly",
+                            initialTitleParams.leftMargin,
+                            finalTitleParams.leftMargin);
+                    Assert.assertEquals(
+                            "Title top margin changed unexpectedly",
+                            initialTitleParams.topMargin,
+                            finalTitleParams.topMargin);
+                    Assert.assertEquals(
+                            "Title right margin changed unexpectedly",
+                            initialTitleParams.rightMargin,
+                            finalTitleParams.rightMargin);
+                    Assert.assertEquals(
+                            "Title bottom margin changed unexpectedly",
+                            initialTitleParams.bottomMargin,
+                            finalTitleParams.bottomMargin);
+                    Assert.assertEquals(
+                            "Title start margin changed unexpectedly",
+                            initialTitleParams.getMarginStart(),
+                            finalTitleParams.getMarginStart());
+                    Assert.assertEquals(
+                            "Title end margin changed unexpectedly",
+                            initialTitleParams.getMarginEnd(),
+                            finalTitleParams.getMarginEnd());
+
+                    // Check radio button margins.
+                    Assert.assertEquals(
+                            "Radio button left margin changed unexpectedly",
+                            initialRadioButtonParams.leftMargin,
+                            finalRadioButtonParams.leftMargin);
+                    Assert.assertEquals(
+                            "Radio button top margin changed unexpectedly",
+                            initialRadioButtonParams.topMargin,
+                            finalRadioButtonParams.topMargin);
+                    Assert.assertEquals(
+                            "Radio button right margin changed unexpectedly",
+                            initialRadioButtonParams.rightMargin,
+                            finalRadioButtonParams.rightMargin);
+                    Assert.assertEquals(
+                            "Radio button bottom margin changed unexpectedly",
+                            initialRadioButtonParams.bottomMargin,
+                            finalRadioButtonParams.bottomMargin);
+                    Assert.assertEquals(
+                            "Radio button start margin changed unexpectedly",
+                            initialRadioButtonParams.getMarginStart(),
+                            finalRadioButtonParams.getMarginStart());
+
+                    Assert.assertEquals(
+                            "Radio button end margin changed unexpectedly",
+                            initialRadioButtonParams.getMarginEnd(),
+                            finalRadioButtonParams.getMarginEnd());
+
+                    // Check root layout padding.
+                    Assert.assertEquals(
+                            "Root padding start changed unexpectedly",
+                            initialRootPaddingStart,
+                            mRichRbHorizontalFullUnchecked.getPaddingStart());
+                    Assert.assertEquals(
+                            "Root padding top changed unexpectedly",
+                            initialRootPaddingTop,
+                            mRichRbHorizontalFullUnchecked.getPaddingTop());
+                    Assert.assertEquals(
+                            "Root padding end changed unexpectedly",
+                            initialRootPaddingEnd,
+                            mRichRbHorizontalFullUnchecked.getPaddingEnd());
+                    Assert.assertEquals(
+                            "Root padding bottom changed unexpectedly",
+                            initialRootPaddingBottom,
+                            mRichRbHorizontalFullUnchecked.getPaddingBottom());
+                });
+    }
 }
diff --git a/components/browsing_data/core/features.cc b/components/browsing_data/core/features.cc
index bfb982a0..9906d1d 100644
--- a/components/browsing_data/core/features.cc
+++ b/components/browsing_data/core/features.cc
@@ -17,5 +17,8 @@
 BASE_FEATURE(kDbdRevampDesktop,
              "DbdRevampDesktop",
              base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kBrowsingHistoryActorIntegrationM1,
+             "BrowsingHistoryActorIntegrationM1",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 }  // namespace browsing_data::features
diff --git a/components/browsing_data/core/features.h b/components/browsing_data/core/features.h
index 0508d49..843acd2 100644
--- a/components/browsing_data/core/features.h
+++ b/components/browsing_data/core/features.h
@@ -14,11 +14,16 @@
 BASE_DECLARE_FEATURE(kBrowsingDataModel);
 #endif  // BUILDFLAG(IS_ANDROID)
 
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 // Enables a revamped Delete Browsing Data dialog. This includes UI changes,
 // updates to history counter logic and removal of the bulk password deletion
 // option from the dialog.
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 BASE_DECLARE_FEATURE(kDbdRevampDesktop);
+
+// Enables the Browsing History Actor Integration M1 feature. This feature
+// introduces new ui and functionality related to the history integration in
+// Chrome.
+BASE_DECLARE_FEATURE(kBrowsingHistoryActorIntegrationM1);
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 }  // namespace browsing_data::features
 
diff --git a/components/collaboration/internal/BUILD.gn b/components/collaboration/internal/BUILD.gn
index 761f231..43ed8ecb 100644
--- a/components/collaboration/internal/BUILD.gn
+++ b/components/collaboration/internal/BUILD.gn
@@ -201,6 +201,10 @@
     "//components/sync:test_support",
     "//testing/gtest",
   ]
+
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
 
 source_set("comments_unit_tests") {
diff --git a/components/content_capture/android/onscreen_content_provider_android.cc b/components/content_capture/android/onscreen_content_provider_android.cc
index 1e5e0b5..df2e071 100644
--- a/components/content_capture/android/onscreen_content_provider_android.cc
+++ b/components/content_capture/android/onscreen_content_provider_android.cc
@@ -86,7 +86,7 @@
         ToJavaObjectOfContentCaptureFrame(env, session[i], offset_y);
     env->SetObjectArrayElement(joa, i, item.obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 }  // namespace
diff --git a/components/content_settings/core/browser/content_settings_info.cc b/components/content_settings/core/browser/content_settings_info.cc
index fc67821..1d6de36 100644
--- a/components/content_settings/core/browser/content_settings_info.cc
+++ b/components/content_settings/core/browser/content_settings_info.cc
@@ -98,7 +98,7 @@
   return false;
 }
 
-bool ContentSettingsInfo::Delegate::CanBeAutoRevoked(
+bool ContentSettingsInfo::Delegate::IsAnyPermissionAllowed(
     PermissionSetting setting) const {
   return std::get<ContentSetting>(setting) == CONTENT_SETTING_ALLOW;
 }
diff --git a/components/content_settings/core/browser/content_settings_info.h b/components/content_settings/core/browser/content_settings_info.h
index f7d7223..abe0ad7 100644
--- a/components/content_settings/core/browser/content_settings_info.h
+++ b/components/content_settings/core/browser/content_settings_info.h
@@ -43,7 +43,7 @@
     std::optional<PermissionSetting> InheritInIncognito(
         const PermissionSetting& setting) const override;
     bool ShouldCoalesceEphemeralState() const override;
-    bool CanBeAutoRevoked(PermissionSetting setting) const override;
+    bool IsAnyPermissionAllowed(PermissionSetting setting) const override;
     bool CanTrackLastVisit() const override;
     base::Value ToValue(const PermissionSetting& setting) const override;
     std::optional<PermissionSetting> FromValue(
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index 75441872..a1e50e1 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -871,6 +871,16 @@
                WebsiteSettingsRegistry::PLATFORM_ANDROID,
            ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE,
            PermissionSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
+
+  Register(ContentSettingsType::DEVICE_ATTRIBUTES, "device-attributes",
+           CONTENT_SETTING_ALLOW, WebsiteSettingsInfo::UNSYNCABLE,
+           /*allowlisted_primary_schemes=*/{},
+           /*valid_settings=*/
+           {CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK},
+           WebsiteSettingsInfo::TOP_ORIGIN_ONLY_SCOPE,
+           WebsiteSettingsRegistry::PLATFORM_CHROMEOS,
+           ContentSettingsInfo::INHERIT_IN_INCOGNITO,
+           PermissionSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
 }
 
 void ContentSettingsRegistry::Register(
diff --git a/components/content_settings/core/browser/content_settings_uma_util.cc b/components/content_settings/core/browser/content_settings_uma_util.cc
index 81f8009..bf90825 100644
--- a/components/content_settings/core/browser/content_settings_uma_util.cc
+++ b/components/content_settings/core/browser/content_settings_uma_util.cc
@@ -160,6 +160,7 @@
     {ContentSettingsType::INITIALIZED_TRANSLATIONS, 137},
     {ContentSettingsType::SUSPICIOUS_NOTIFICATION_IDS, 138},
     {ContentSettingsType::GEOLOCATION_WITH_OPTIONS, 139},
+    {ContentSettingsType::DEVICE_ATTRIBUTES, 140},
 
     // As mentioned at the top, please don't forget to update ContentType in
     // enums.xml when you add entries here!
diff --git a/components/content_settings/core/browser/content_settings_utils.cc b/components/content_settings/core/browser/content_settings_utils.cc
index f54fb71..9ef38f6 100644
--- a/components/content_settings/core/browser/content_settings_utils.cc
+++ b/components/content_settings/core/browser/content_settings_utils.cc
@@ -242,7 +242,7 @@
     if (!setting.has_value()) {
       return false;
     }
-    return permission_settings_info->delegate().CanBeAutoRevoked(
+    return permission_settings_info->delegate().IsAnyPermissionAllowed(
                setting.value()) &&
            CanTrackLastVisit(type);
   } else {
diff --git a/components/content_settings/core/browser/geolocation_setting_delegate.cc b/components/content_settings/core/browser/geolocation_setting_delegate.cc
index af96461..992fb336 100644
--- a/components/content_settings/core/browser/geolocation_setting_delegate.cc
+++ b/components/content_settings/core/browser/geolocation_setting_delegate.cc
@@ -85,7 +85,7 @@
   return setting;
 }
 
-bool GeolocationSettingDelegate::CanBeAutoRevoked(
+bool GeolocationSettingDelegate::IsAnyPermissionAllowed(
     PermissionSetting setting) const {
   return std::get<GeolocationSetting>(setting).approximate ==
          PermissionOption::kAllowed;
diff --git a/components/content_settings/core/browser/geolocation_setting_delegate.h b/components/content_settings/core/browser/geolocation_setting_delegate.h
index bee8850..40486f56 100644
--- a/components/content_settings/core/browser/geolocation_setting_delegate.h
+++ b/components/content_settings/core/browser/geolocation_setting_delegate.h
@@ -21,7 +21,7 @@
   std::optional<PermissionSetting> InheritInIncognito(
       const PermissionSetting& setting) const override;
 
-  bool CanBeAutoRevoked(PermissionSetting setting) const override;
+  bool IsAnyPermissionAllowed(PermissionSetting setting) const override;
   bool CanTrackLastVisit() const override;
 
   bool ShouldCoalesceEphemeralState() const override;
diff --git a/components/content_settings/core/browser/permission_settings_info.h b/components/content_settings/core/browser/permission_settings_info.h
index 48db53a..dab27cb 100644
--- a/components/content_settings/core/browser/permission_settings_info.h
+++ b/components/content_settings/core/browser/permission_settings_info.h
@@ -37,8 +37,11 @@
     virtual std::optional<PermissionSetting> InheritInIncognito(
         const PermissionSetting& setting) const = 0;
 
-    // Returns whether the permission setting can be auto-revoked by SafetyHub.
-    virtual bool CanBeAutoRevoked(PermissionSetting setting) const = 0;
+    // Returns if at least some of the permission setting is allowed. Used e.g.
+    // to decide whether the permission setting can be auto-revoked by
+    // SafetyHub.
+    virtual bool IsAnyPermissionAllowed(PermissionSetting setting) const = 0;
+
     // Returns whether the permission setting supports expiration tracking.
     virtual bool CanTrackLastVisit() const = 0;
 
diff --git a/components/content_settings/core/common/content_settings_types.mojom b/components/content_settings/core/common/content_settings_types.mojom
index 45a46d2..12a13c6417 100644
--- a/components/content_settings/core/common/content_settings_types.mojom
+++ b/components/content_settings/core/common/content_settings_types.mojom
@@ -499,5 +499,9 @@
   // site. Used for recovering notification contents from the database if the
   // user decides they would like to see all of these notifications.
   SUSPICIOUS_NOTIFICATION_IDS,
+
+  // Setting for enabling the Device Attributes API. Spec link:
+  // https://wicg.github.io/WebApiDevice/device_attributes/
+  DEVICE_ATTRIBUTES,
 };
 // LINT.ThenChange(//components/content_settings/core/browser/content_settings_uma_util.cc:kHistogramValue)
diff --git a/components/contextual_search/core/browser/contextual_search_context.h b/components/contextual_search/core/browser/contextual_search_context.h
index 68cdd0a..9a176b8 100644
--- a/components/contextual_search/core/browser/contextual_search_context.h
+++ b/components/contextual_search/core/browser/contextual_search_context.h
@@ -147,6 +147,12 @@
     apply_lang_hint_ = apply_lang_hint;
   }
 
+  // Returns whether the snippet should be used as the touch to search subtitle.
+  bool GetUseSnippetAsSubtitle() const { return use_snippet_as_subtitle_; }
+  void SetUseSnippetAsSubtitle(bool use_snippet_as_subtitle) {
+    use_snippet_as_subtitle_ = use_snippet_as_subtitle;
+  }
+
   virtual base::WeakPtr<ContextualSearchContext> AsWeakPtr();
 
  private:
@@ -172,6 +178,7 @@
   TranslationLanguages translation_languages_;
   std::string related_searches_stamp_;
   bool apply_lang_hint_ = false;
+  bool use_snippet_as_subtitle_ = false;
 
   base::WeakPtrFactory<ContextualSearchContext> weak_ptr_factory_{this};
 };
diff --git a/components/contextual_search/core/browser/contextual_search_delegate_impl.cc b/components/contextual_search/core/browser/contextual_search_delegate_impl.cc
index d15523d..8e2b1c8 100644
--- a/components/contextual_search/core/browser/contextual_search_delegate_impl.cc
+++ b/components/contextual_search/core/browser/contextual_search_delegate_impl.cc
@@ -426,7 +426,8 @@
       context->GetTranslationLanguages().detected_language,
       context->GetTranslationLanguages().target_language,
       context->GetTranslationLanguages().fluent_languages,
-      context->GetRelatedSearchesStamp(), context->GetApplyLangHint());
+      context->GetRelatedSearchesStamp(), context->GetApplyLangHint(),
+      context->GetUseSnippetAsSubtitle());
 
   search_terms_args.contextual_search_params = params;
 
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.cc b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
index 019ec35..2144c9e 100644
--- a/components/cronet/android/cronet_bidirectional_stream_adapter.cc
+++ b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
@@ -219,7 +219,7 @@
       new PendingWriteData(env, jbyte_buffers, jbyte_buffers_pos,
                            jbyte_buffers_limit, jend_of_stream));
   for (size_t i = 0; i < buffers_array_size; ++i) {
-    ScopedJavaLocalRef<jobject> jbuffer(
+    auto jbuffer = ScopedJavaLocalRef<jobject>::Adopt(
         env, env->GetObjectArrayElement(
                  pending_write_data->jwrite_buffer_list.obj(), i));
     void* data = env->GetDirectBufferAddress(jbuffer.obj());
diff --git a/components/cronet/android/io_buffer_with_byte_buffer.cc b/components/cronet/android/io_buffer_with_byte_buffer.cc
index 9e8d0f3..0855bee 100644
--- a/components/cronet/android/io_buffer_with_byte_buffer.cc
+++ b/components/cronet/android/io_buffer_with_byte_buffer.cc
@@ -37,7 +37,7 @@
     : io_buffer_(std::move(io_buffer)), io_buffer_len_(io_buffer_len) {
   // An intermediate ScopedJavaLocalRef is needed here to release the local
   // reference created by env->NewDirectByteBuffer().
-  base::android::ScopedJavaLocalRef<jobject> java_buffer(
+  auto java_buffer = base::android::ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(io_buffer_->data(), io_buffer_len_));
   byte_buffer_.Reset(env, java_buffer);
 }
diff --git a/components/device_signals/core/browser/BUILD.gn b/components/device_signals/core/browser/BUILD.gn
index 89c8b7d2..ed670939 100644
--- a/components/device_signals/core/browser/BUILD.gn
+++ b/components/device_signals/core/browser/BUILD.gn
@@ -70,13 +70,18 @@
     sources += [ "android/android_os_signals_collector.cc" ]
   } else if (is_win || is_mac || is_linux) {
     public += [
+      "agent_signals_collector.h",
+      "crowdstrike_client.h",
       "desktop/desktop_os_signals_collector.h",
       "detected_agent_client.h",
     ]
     sources += [
+      "agent_signals_collector.cc",
+      "crowdstrike_client.cc",
       "desktop/desktop_os_signals_collector.cc",
       "detected_agent_client.cc",
     ]
+    deps += [ "//services/data_decoder/public/cpp" ]
   }
 
   if (is_win) {
@@ -96,19 +101,6 @@
   if (is_chromeos) {
     sources += [ "chromeos/browser_utils_chromeos.cc" ]
   }
-
-  if (is_win || is_mac) {
-    public += [
-      "agent_signals_collector.h",
-      "crowdstrike_client.h",
-    ]
-    sources += [
-      "agent_signals_collector.cc",
-      "crowdstrike_client.cc",
-    ]
-
-    deps += [ "//services/data_decoder/public/cpp" ]
-  }
 }
 
 static_library("test_support") {
@@ -163,15 +155,10 @@
 
   if (is_win || is_mac || is_linux) {
     sources += [
-      "desktop/desktop_os_signals_collector_unittest.cc",
-      "detected_agent_client_unittest.cc",
-    ]
-  }
-
-  if (is_win || is_mac) {
-    sources += [
       "agent_signals_collector_unittest.cc",
       "crowdstrike_client_unittest.cc",
+      "desktop/desktop_os_signals_collector_unittest.cc",
+      "detected_agent_client_unittest.cc",
     ]
     deps += [ "//services/data_decoder/public/cpp:test_support" ]
   }
diff --git a/components/device_signals/core/browser/agent_signals_collector.cc b/components/device_signals/core/browser/agent_signals_collector.cc
index 8f9bc2c..2807c0e 100644
--- a/components/device_signals/core/browser/agent_signals_collector.cc
+++ b/components/device_signals/core/browser/agent_signals_collector.cc
@@ -6,26 +6,29 @@
 
 #include <utility>
 
+#include "base/barrier_callback.h"
 #include "base/check.h"
 #include "base/functional/bind.h"
 #include "base/time/time.h"
 #include "components/device_signals/core/browser/crowdstrike_client.h"
+#include "components/device_signals/core/browser/detected_agent_client.h"
 #include "components/device_signals/core/browser/metrics_utils.h"
-#include "components/device_signals/core/browser/signals_types.h"
 #include "components/device_signals/core/browser/user_permission_service.h"
-#include "components/device_signals/core/common/common_types.h"
 
 namespace device_signals {
 
 AgentSignalsCollector::AgentSignalsCollector(
-    std::unique_ptr<CrowdStrikeClient> crowdstrike_client)
+    std::unique_ptr<CrowdStrikeClient> crowdstrike_client,
+    std::unique_ptr<DetectedAgentClient> detected_agent_client)
     : BaseSignalsCollector({
           {SignalName::kAgent,
            base::BindRepeating(&AgentSignalsCollector::GetAgentSignal,
                                base::Unretained(this))},
       }),
-      crowdstrike_client_(std::move(crowdstrike_client)) {
-  DCHECK(crowdstrike_client_);
+      crowdstrike_client_(std::move(crowdstrike_client)),
+      detected_agent_client_(std::move(detected_agent_client)) {
+  CHECK(crowdstrike_client_);
+  CHECK(detected_agent_client_);
 }
 
 AgentSignalsCollector::~AgentSignalsCollector() = default;
@@ -35,41 +38,97 @@
     const SignalsAggregationRequest& request,
     SignalsAggregationResponse& response,
     base::OnceClosure done_closure) {
-  if (permission != UserPermission::kGranted) {
-    std::move(done_closure).Run();
-    return;
-  }
-  crowdstrike_client_->GetIdentifiers(
-      base::BindOnce(&AgentSignalsCollector::OnCrowdStrikeSignalCollected,
+  auto barrier_cb = base::BarrierCallback<AgentSignalsResponse>(
+      /*num_callbacks=*/1,
+      base::BindOnce(&AgentSignalsCollector::OnSignalsCollected,
                      weak_factory_.GetWeakPtr(), base::TimeTicks::Now(),
                      std::ref(response), std::move(done_closure)));
+
+  GetCrowdstrikeIdentifierSignals(permission, request, response, barrier_cb);
+}
+
+void AgentSignalsCollector::GetDetectedAgentSignal(
+    const SignalsAggregationRequest request,
+    SignalsAggregationResponse response,
+    AgentSignalsResponseCallback agent_response_cb) {
+  // TODO(430135330): Implementing in a followup.
+}
+
+void AgentSignalsCollector::OnDetectedAgentSignalCollected(
+    SignalsAggregationResponse& response,
+    AgentSignalsResponseCallback agent_response_cb,
+    std::vector<Agents> agent_signals) {
+  // TODO(430135330): Implementing in a followup.
+}
+
+void AgentSignalsCollector::GetCrowdstrikeIdentifierSignals(
+    UserPermission permission,
+    const SignalsAggregationRequest request,
+    SignalsAggregationResponse response,
+    AgentSignalsResponseCallback agent_response_cb) {
+  if (permission != UserPermission::kGranted) {
+    agent_response_cb.Run(AgentSignalsResponse());
+    return;
+  }
+
+  crowdstrike_client_->GetIdentifiers(base::BindOnce(
+      &AgentSignalsCollector::OnCrowdStrikeSignalCollected,
+      weak_factory_.GetWeakPtr(), std::ref(response), agent_response_cb));
 }
 
 void AgentSignalsCollector::OnCrowdStrikeSignalCollected(
-    base::TimeTicks start_time,
     SignalsAggregationResponse& response,
-    base::OnceClosure done_closure,
+    AgentSignalsResponseCallback agent_response_cb,
     std::optional<CrowdStrikeSignals> agent_signals,
     std::optional<SignalCollectionError> error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  AgentSignalsResponse signal_response;
+
   if (agent_signals || error) {
-    AgentSignalsResponse signal_response;
     if (agent_signals) {
       signal_response.crowdstrike_signals = std::move(agent_signals);
     }
 
     if (error) {
-      LogSignalCollectionFailed(SignalName::kAgent, start_time, error.value(),
-                                /*is_top_level_error=*/false);
       signal_response.collection_error = error.value();
-    } else {
-      LogSignalCollectionSucceeded(SignalName::kAgent, start_time,
-                                   /*signal_collection_size=*/std::nullopt);
     }
-
-    response.agent_signals_response = std::move(signal_response);
   }
 
+  agent_response_cb.Run(std::move(signal_response));
+}
+
+void AgentSignalsCollector::OnSignalsCollected(
+    base::TimeTicks start_time,
+    SignalsAggregationResponse& response,
+    base::OnceClosure done_closure,
+    std::vector<AgentSignalsResponse> agent_signals_responses) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  AgentSignalsResponse signal_response;
+  for (AgentSignalsResponse agent_signals_response : agent_signals_responses) {
+    if (agent_signals_response.collection_error) {
+      signal_response.collection_error =
+          std::move(agent_signals_response.collection_error);
+    }
+
+    if (agent_signals_response.crowdstrike_signals) {
+      signal_response.crowdstrike_signals =
+          std::move(agent_signals_response.crowdstrike_signals);
+    }
+  }
+
+  if (signal_response.collection_error) {
+    LogSignalCollectionFailed(SignalName::kAgent, start_time,
+                              signal_response.collection_error.value(),
+                              /*is_top_level_error=*/false);
+  } else {
+    LogSignalCollectionSucceeded(SignalName::kAgent, start_time,
+                                 /*signal_collection_size=*/std::nullopt);
+  }
+
+  if (signal_response != AgentSignalsResponse()) {
+    response.agent_signals_response = std::move(signal_response);
+  }
   std::move(done_closure).Run();
 }
 
diff --git a/components/device_signals/core/browser/agent_signals_collector.h b/components/device_signals/core/browser/agent_signals_collector.h
index 63a4c027..3e19e72 100644
--- a/components/device_signals/core/browser/agent_signals_collector.h
+++ b/components/device_signals/core/browser/agent_signals_collector.h
@@ -13,6 +13,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "components/device_signals/core/browser/base_signals_collector.h"
+#include "components/device_signals/core/browser/signals_types.h"
+#include "components/device_signals/core/common/common_types.h"
 
 namespace base {
 class TimeTicks;
@@ -21,6 +23,7 @@
 namespace device_signals {
 
 class CrowdStrikeClient;
+class DetectedAgentClient;
 struct CrowdStrikeSignals;
 enum class SignalCollectionError;
 
@@ -28,8 +31,12 @@
 // agents running on the device.
 class AgentSignalsCollector : public BaseSignalsCollector {
  public:
-  explicit AgentSignalsCollector(
-      std::unique_ptr<CrowdStrikeClient> crowdstrike_client);
+  using AgentSignalsResponseCallback =
+      base::RepeatingCallback<void(AgentSignalsResponse)>;
+
+  AgentSignalsCollector(
+      std::unique_ptr<CrowdStrikeClient> crowdstrike_client,
+      std::unique_ptr<DetectedAgentClient> detected_agent_client);
 
   ~AgentSignalsCollector() override;
 
@@ -37,8 +44,8 @@
   AgentSignalsCollector& operator=(const AgentSignalsCollector&) = delete;
 
  private:
-  // Collection function for the Agent signal. `request` is ignored since the
-  // agent signal does not require parameters. `response` will be passed along
+  // Collection function for the Agent signal. `request` contains the details on
+  // which agent signals should be collected. `response` will be passed along
   // and the signal values will be set on it when available. `done_closure` will
   // be invoked when signal collection is complete.
   void GetAgentSignal(UserPermission permission,
@@ -46,20 +53,55 @@
                       SignalsAggregationResponse& response,
                       base::OnceClosure done_closure);
 
-  // Invoked when the CrowdStrike client returns the collected agent
-  // signals as `agent_signals`. Will update `response` with the
-  // signal collection outcome, and invoke `done_closure` to asynchronously
-  // notify the caller of the completion of this request.
-  void OnCrowdStrikeSignalCollected(
-      base::TimeTicks start_time,
+  // Collection function for the Detected Agent signal. `request` contains the
+  // details on which agent signals should be collected.
+  // Invokes OnDetectedAgentSignalCollected when signal collection is complete.
+  void GetDetectedAgentSignal(const SignalsAggregationRequest request,
+                              SignalsAggregationResponse response,
+                              AgentSignalsResponseCallback agent_response_cb);
+
+  // Invoked when the detected `agent_signals` collection is complete.
+  // Will invoke `agent_response_cb` with the signal collection outcome to
+  // asynchronously notify the caller of the completion of this request.
+  void OnDetectedAgentSignalCollected(
       SignalsAggregationResponse& response,
-      base::OnceClosure done_closure,
+      AgentSignalsResponseCallback agent_response_cb,
+      std::vector<Agents> agent_signals);
+
+  // Collection function for the Crowdstrike identifiers signal. `request`
+  // contains the details on which agent signals should be collected.
+  // Invokes OnCrowdStrikeSignalCollected when signal collection is complete.
+  void GetCrowdstrikeIdentifierSignals(
+      UserPermission permission,
+      const SignalsAggregationRequest request,
+      SignalsAggregationResponse response,
+      AgentSignalsResponseCallback agent_response_cb);
+
+  // Invoked when the CrowdStrike client returns the collected agent
+  // signals as `agent_signals`. Will invoke `agent_response_cb` with the signal
+  // collection outcome to asynchronously notify the caller of the completion of
+  // this request.
+  void OnCrowdStrikeSignalCollected(
+      SignalsAggregationResponse& response,
+      AgentSignalsResponseCallback agent_response_cb,
       std::optional<CrowdStrikeSignals> agent_signals,
       std::optional<SignalCollectionError> error);
 
+  // Invoked when all `agent_signals_responses` were collected. Updates the
+  // `response` with the collected `agent_signals_responses` and invokes the
+  // `done_closure` with the `response` once complete.
+  void OnSignalsCollected(
+      base::TimeTicks start_time,
+      SignalsAggregationResponse& response,
+      base::OnceClosure done_closure,
+      std::vector<AgentSignalsResponse> agent_signals_responses);
+
   // Instance used to collect signals from a CrowdStrike agent.
   std::unique_ptr<CrowdStrikeClient> crowdstrike_client_;
 
+  // Instance used to collect signals for installed security agents.
+  std::unique_ptr<DetectedAgentClient> detected_agent_client_;
+
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<AgentSignalsCollector> weak_factory_{this};
 };
diff --git a/components/device_signals/core/browser/agent_signals_collector_unittest.cc b/components/device_signals/core/browser/agent_signals_collector_unittest.cc
index 4adf6e8..f3bc7dfd 100644
--- a/components/device_signals/core/browser/agent_signals_collector_unittest.cc
+++ b/components/device_signals/core/browser/agent_signals_collector_unittest.cc
@@ -6,14 +6,18 @@
 
 #include <utility>
 
+#include "base/files/scoped_temp_dir.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "components/device_signals/core/browser/crowdstrike_client.h"
+#include "components/device_signals/core/browser/detected_agent_client.h"
 #include "components/device_signals/core/browser/signals_types.h"
 #include "components/device_signals/core/browser/user_permission_service.h"
 #include "components/device_signals/core/common/common_types.h"
+#include "components/device_signals/core/common/signals_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -39,22 +43,42 @@
 MockCrowdStrikeClient::MockCrowdStrikeClient() = default;
 MockCrowdStrikeClient::~MockCrowdStrikeClient() = default;
 
+class MockDetectedAgentClient : public DetectedAgentClient {
+ public:
+  MockDetectedAgentClient();
+  ~MockDetectedAgentClient() override;
+
+  MOCK_METHOD(void,
+              GetAgents,
+              (base::OnceCallback<void(std::vector<Agents>)>),
+              (override));
+};
+
+MockDetectedAgentClient::MockDetectedAgentClient() = default;
+MockDetectedAgentClient::~MockDetectedAgentClient() = default;
+
 }  // namespace
 
 class AgentSignalsCollectorTest : public testing::Test {
  protected:
-  AgentSignalsCollectorTest() {
+  void CreateCollector() {
+    auto mocked_detected_agent_client =
+        std::make_unique<StrictMock<MockDetectedAgentClient>>();
+    mocked_detected_agent_client_ = mocked_detected_agent_client.get();
+
     auto mocked_crowdstrike_client =
         std::make_unique<StrictMock<MockCrowdStrikeClient>>();
     mocked_crowdstrike_client_ = mocked_crowdstrike_client.get();
 
     collector_ = std::make_unique<AgentSignalsCollector>(
-        std::move(mocked_crowdstrike_client));
+        std::move(mocked_crowdstrike_client),
+        std::move(mocked_detected_agent_client));
   }
 
   void RunTest(
       std::optional<CrowdStrikeSignals> returned_signals,
       std::optional<SignalCollectionError> returned_error = std::nullopt) {
+    CreateCollector();
     EXPECT_CALL(*mocked_crowdstrike_client_, GetIdentifiers(_))
         .WillOnce(Invoke(
             [&returned_signals, &returned_error](
@@ -117,6 +141,8 @@
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   raw_ptr<StrictMock<MockCrowdStrikeClient>, DanglingUntriaged>
       mocked_crowdstrike_client_;
+  raw_ptr<StrictMock<MockDetectedAgentClient>, DanglingUntriaged>
+      mocked_detected_agent_client_;
   std::unique_ptr<AgentSignalsCollector> collector_;
   base::HistogramTester histogram_tester_;
 };
@@ -124,6 +150,7 @@
 // Test that runs a sanity check on the set of signals supported by this
 // collector. Will need to be updated if new signals become supported.
 TEST_F(AgentSignalsCollectorTest, SupportedSignalNames) {
+  CreateCollector();
   const std::array<SignalName, 1> supported_signals{{SignalName::kAgent}};
 
   const auto names_set = collector_->GetSupportedSignalNames();
@@ -136,6 +163,7 @@
 
 // Tests that an unsupported signal is marked as unsupported.
 TEST_F(AgentSignalsCollectorTest, GetSignal_Unsupported) {
+  CreateCollector();
   SignalName signal_name = SignalName::kAntiVirus;
   SignalsAggregationRequest empty_request;
   SignalsAggregationResponse response;
@@ -152,6 +180,7 @@
 
 // Tests that signal collection is halted if permission is not sufficient.
 TEST_F(AgentSignalsCollectorTest, GetSignal_MissingConsent) {
+  CreateCollector();
   SignalName signal_name = SignalName::kAgent;
   SignalsAggregationRequest empty_request;
   SignalsAggregationResponse response;
diff --git a/components/device_signals/core/browser/crowdstrike_client.cc b/components/device_signals/core/browser/crowdstrike_client.cc
index 22dae4b..0d43295 100644
--- a/components/device_signals/core/browser/crowdstrike_client.cc
+++ b/components/device_signals/core/browser/crowdstrike_client.cc
@@ -146,11 +146,7 @@
 
 // static
 std::unique_ptr<CrowdStrikeClient> CrowdStrikeClient::Create() {
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
   return std::make_unique<CrowdStrikeClientImpl>(GetCrowdStrikeZtaFilePath());
-#else
-  NOTREACHED();
-#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 }
 
 std::unique_ptr<CrowdStrikeClient> CrowdStrikeClient::CreateForTesting(
@@ -167,6 +163,10 @@
 
 void CrowdStrikeClientImpl::GetIdentifiers(SignalsCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (zta_file_path_.empty()) {
+    std::move(callback).Run(/*signals=*/std::nullopt, /*error=*/std::nullopt);
+    return;
+  }
   const auto& cached_values = cached_signals_.Get();
   if (cached_values) {
     std::move(callback).Run(cached_values.value(), /*error=*/std::nullopt);
diff --git a/components/device_signals/core/browser/crowdstrike_client_unittest.cc b/components/device_signals/core/browser/crowdstrike_client_unittest.cc
index d697440..d1cb0bb 100644
--- a/components/device_signals/core/browser/crowdstrike_client_unittest.cc
+++ b/components/device_signals/core/browser/crowdstrike_client_unittest.cc
@@ -130,8 +130,11 @@
 #endif
 
     ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+  }
 
-    client_ = CrowdStrikeClient::CreateForTesting(GetDataFilePath());
+  void InitializeClient(bool empty_file = true) {
+    client_ = CrowdStrikeClient::CreateForTesting(
+        empty_file ? GetDataFilePath() : base::FilePath());
   }
 
   void CreateFakeFileWithContent(const std::string& file_content) {
@@ -197,7 +200,17 @@
   std::unique_ptr<CrowdStrikeClient> client_;
 };
 
+TEST_F(CrowdStrikeClientTest, Identifiers_EmptyFilePath) {
+  InitializeClient(/*empty_file=*/true);
+  // Expect no signals and no error.
+  EXPECT_FALSE(GetSignalCollectionError());
+
+  // No value logged, not having the file available is not considered a failure.
+  ValidateHistogram(std::nullopt);
+}
+
 TEST_F(CrowdStrikeClientTest, Identifiers_NoFile) {
+  InitializeClient();
   // Expect no signals and no error.
   EXPECT_FALSE(GetSignalCollectionError());
 
@@ -206,6 +219,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_EmptyFile) {
+  InitializeClient();
   CreateFakeFileWithContent("");
 
   // Expect no signals and no error.
@@ -216,6 +230,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_NotJwt) {
+  InitializeClient();
   CreateFakeFileWithContent("some.random.content");
 
   const auto& error = GetSignalCollectionError();
@@ -226,6 +241,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_MaxDataSize) {
+  InitializeClient();
   std::string content(33 * 1024, 'a');
   CreateFakeFileWithContent(content);
 
@@ -237,6 +253,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_DecodingFailed) {
+  InitializeClient();
   CreateFakeFileWithContent("some.random%%.content");
 
   const auto& error = GetSignalCollectionError();
@@ -247,6 +264,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_MissingJwtSection) {
+  InitializeClient();
   constexpr char kFakeJwtZtaContent[] =
       "eyJhbGciOiJSUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0."
       "eyJhc3Nlc3NtZW50Ijp7Im92ZXJhbGwiOjU1LCJvcyI6NTAsInNlbnNvcl9jb25maWciOjYw"
@@ -264,6 +282,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_MissingSub) {
+  InitializeClient();
   // JWT value where `sub` is missing from the payload.
   static constexpr char kFakeJwtZtaContent[] =
       "eyJhbGciOiJSUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0."
@@ -292,6 +311,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_Success) {
+  InitializeClient();
   CreateFakeFileWithContent(kValidFakeJwtZtaContent);
   auto signals = GetSignals();
 
@@ -303,6 +323,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_Success_CachedValue) {
+  InitializeClient();
   CreateFakeFileWithContent(kValidFakeJwtZtaContent);
   auto signals = GetSignals();
 
@@ -331,6 +352,7 @@
 // Tests that only having the customer ID in the registry is treated
 // as insufficient, and no value is returned.
 TEST_F(CrowdStrikeClientTest, Identifiers_NoFile_RegistryNoAgentId) {
+  InitializeClient();
   SetUpCrowdStrikeInfo(kFakeHexCSCustomerId, std::nullopt);
 
   auto signals = GetSignals();
@@ -341,6 +363,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_NoFile_RegistryNoCustomerId) {
+  InitializeClient();
   SetUpCrowdStrikeInfo(std::nullopt, kFakeHexCSAgentId);
 
   auto signals = GetSignals();
@@ -360,6 +383,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_FileHasPrecendence) {
+  InitializeClient();
   SetUpCrowdStrikeInfo(kFakeHexCSCustomerId, kFakeHexCSAgentId);
 
   CreateFakeFileWithContent(kValidFakeJwtZtaContent);
@@ -372,6 +396,7 @@
 }
 
 TEST_F(CrowdStrikeClientTest, Identifiers_DecodingFailed_RegistryFallback) {
+  InitializeClient();
   CreateFakeFileWithContent("some.random%%.content");
   SetUpCrowdStrikeInfo(kFakeHexCSCustomerId, kFakeHexCSAgentId);
 
diff --git a/components/device_signals/core/browser/signals_types.h b/components/device_signals/core/browser/signals_types.h
index 102bc2f9..9676a88 100644
--- a/components/device_signals/core/browser/signals_types.h
+++ b/components/device_signals/core/browser/signals_types.h
@@ -286,6 +286,7 @@
   ~AgentSignalsResponse() override;
 
   std::optional<CrowdStrikeSignals> crowdstrike_signals = std::nullopt;
+  std::vector<Agents> detected_agents{};
 };
 
 // Request struct containing properties that will be used by the
diff --git a/components/device_signals/core/common/linux/platform_utils_linux.cc b/components/device_signals/core/common/linux/platform_utils_linux.cc
index 8ca20919..4749c72 100644
--- a/components/device_signals/core/common/linux/platform_utils_linux.cc
+++ b/components/device_signals/core/common/linux/platform_utils_linux.cc
@@ -63,6 +63,11 @@
   return base::FilePath(kCrowdstrikeAgentPath);
 }
 
+base::FilePath GetCrowdStrikeZtaFilePath() {
+  // ZTA files currently are not stored locally on linux platforms.
+  return base::FilePath();
+}
+
 // Implements the logic from the native client setup script. It reads the
 // setting value straight from gsettings but picks the schema relevant to the
 // currently active desktop environment.
diff --git a/components/device_signals/core/common/platform_utils.h b/components/device_signals/core/common/platform_utils.h
index ed40fd6f..afcf5f1 100644
--- a/components/device_signals/core/common/platform_utils.h
+++ b/components/device_signals/core/common/platform_utils.h
@@ -40,9 +40,7 @@
 // Returns the Crowdstrike Falcon agent install path.
 base::FilePath GetCrowdStrikeAgentInstallPath();
 
-#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 base::FilePath GetCrowdStrikeZtaFilePath();
-#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
 
 std::string GetOsName();
 std::string GetOsVersion();
diff --git a/components/embedder_support/android/util/input_stream.cc b/components/embedder_support/android/util/input_stream.cc
index e90ce61..d857e893 100644
--- a/components/embedder_support/android/util/input_stream.cc
+++ b/components/embedder_support/android/util/input_stream.cc
@@ -94,7 +94,7 @@
   JNIEnv* env = AttachCurrentThread();
   if (!buffer_.obj()) {
     // Allocate transfer buffer.
-    base::android::ScopedJavaLocalRef<jbyteArray> temp(
+    auto temp = base::android::ScopedJavaLocalRef<jbyteArray>::Adopt(
         env, env->NewByteArray(GetIntermediateBufferSize()));
     buffer_.Reset(temp);
     if (ClearException(env))
diff --git a/components/enterprise/BUILD.gn b/components/enterprise/BUILD.gn
index aab2ae3..435039a0 100644
--- a/components/enterprise/BUILD.gn
+++ b/components/enterprise/BUILD.gn
@@ -10,6 +10,8 @@
     "browser/reporting/browser_report_generator.h",
     "browser/reporting/chrome_profile_request_generator.cc",
     "browser/reporting/chrome_profile_request_generator.h",
+    "browser/reporting/cloud_profile_reporting_policy_handler.cc",
+    "browser/reporting/cloud_profile_reporting_policy_handler.h",
     "browser/reporting/cloud_reporting_frequency_policy_handler.cc",
     "browser/reporting/cloud_reporting_frequency_policy_handler.h",
     "browser/reporting/cloud_reporting_policy_handler.cc",
@@ -61,13 +63,6 @@
     ]
   }
 
-  if (!is_ios) {
-    sources += [
-      "browser/reporting/cloud_profile_reporting_policy_handler.cc",
-      "browser/reporting/cloud_profile_reporting_policy_handler.h",
-    ]
-  }
-
   if (!is_ios && !is_android) {
     sources += [
       "browser/promotion/promotion_eligibility_checker.cc",
diff --git a/components/enterprise/connectors/core/reporting_event_router.cc b/components/enterprise/connectors/core/reporting_event_router.cc
index d8b0519..0613bed0 100644
--- a/components/enterprise/connectors/core/reporting_event_router.cc
+++ b/components/enterprise/connectors/core/reporting_event_router.cc
@@ -93,8 +93,7 @@
   std::optional<ReportingSettings> settings =
       reporting_client_->GetReportingSettings();
   std::unique_ptr<url_matcher::URLMatcher> matcher =
-      CreateURLMatcherForOptInEvent(settings.value(),
-                                    enterprise_connectors::kKeyLoginEvent);
+      CreateURLMatcherForOptInEvent(settings.value(), kKeyLoginEvent);
   if (!IsUrlMatched(matcher.get(), url)) {
     return;
   }
@@ -260,8 +259,7 @@
   std::optional<ReportingSettings> settings =
       reporting_client_->GetReportingSettings();
   std::string active_user;
-  if (base::FeatureList::IsEnabled(
-          enterprise_connectors::kEnterpriseActiveUserDetection)) {
+  if (base::FeatureList::IsEnabled(kEnterpriseActiveUserDetection)) {
     active_user = reporting_client_->GetContentAreaAccountEmail(url);
   }
 
@@ -282,8 +280,7 @@
     base::Value::Dict event;
     event.Set(kKeyUrl, url.spec());
     EventResult event_result = GetEventResultFromThreatType(threat_type);
-    event.Set(kKeyClickedThrough,
-              event_result == enterprise_connectors::EventResult::BYPASSED);
+    event.Set(kKeyClickedThrough, event_result == EventResult::BYPASSED);
     if (!threat_type.empty()) {
       event.Set(kKeyThreatType, threat_type);
     }
@@ -292,8 +289,7 @@
       event.Set(kKeyWebAppSignedInAccount, active_user);
     }
     AddTriggeredRuleInfoToUrlFilteringInterstitialEvent(response, event);
-    event.Set(kKeyEventResult,
-              enterprise_connectors::EventResultToString(event_result));
+    event.Set(kKeyEventResult, EventResultToString(event_result));
 
     if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
       AddReferrerChainToEvent(referrer_chain, event);
@@ -334,17 +330,15 @@
     event.Set(kKeyReason, reason);
     event.Set(kKeyNetErrorCode, net_error_code);
     event.Set(kKeyClickedThrough, true);
-    event.Set(kKeyEventResult,
-              enterprise_connectors::EventResultToString(
-                  enterprise_connectors::EventResult::BYPASSED));
+    event.Set(kKeyEventResult, EventResultToString(EventResult::BYPASSED));
 
     if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
       AddReferrerChainToEvent(referrer_chain, event);
     }
 
     reporting_client_->ReportEventWithTimestampDeprecated(
-        enterprise_connectors::kKeyInterstitialEvent,
-        std::move(settings.value()), std::move(event), base::Time::Now(),
+        kKeyInterstitialEvent, std::move(settings.value()), std::move(event),
+        base::Time::Now(),
         /*include_profile_user_name=*/true);
   }
 }
@@ -361,9 +355,8 @@
 
   std::optional<ReportingSettings> settings =
       reporting_client_->GetReportingSettings();
-  enterprise_connectors::EventResult event_result =
-      proceed_anyway_disabled ? enterprise_connectors::EventResult::BLOCKED
-                              : enterprise_connectors::EventResult::WARNED;
+  EventResult event_result =
+      proceed_anyway_disabled ? EventResult::BLOCKED : EventResult::WARNED;
 
   if (base::FeatureList::IsEnabled(
           policy::kUploadRealtimeReportingEventsUsingProto)) {
@@ -382,16 +375,15 @@
     event.Set(kKeyReason, reason);
     event.Set(kKeyNetErrorCode, net_error_code);
     event.Set(kKeyClickedThrough, false);
-    event.Set(kKeyEventResult,
-              enterprise_connectors::EventResultToString(event_result));
+    event.Set(kKeyEventResult, EventResultToString(event_result));
 
     if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
       AddReferrerChainToEvent(referrer_chain, event);
     }
 
     reporting_client_->ReportEventWithTimestampDeprecated(
-        enterprise_connectors::kKeyInterstitialEvent,
-        std::move(settings.value()), std::move(event), base::Time::Now(),
+        kKeyInterstitialEvent, std::move(settings.value()), std::move(event),
+        base::Time::Now(),
         /*include_profile_user_name=*/true);
   }
 }
@@ -446,17 +438,15 @@
       event.Set(kKeyContentSize, base::Int64ToValue(content_size));
     }
     event.Set(kKeyTrigger, trigger);
-    event.Set(kKeyEventResult,
-              enterprise_connectors::EventResultToString(event_result));
-    event.Set(kKeyClickedThrough,
-              event_result == enterprise_connectors::EventResult::BYPASSED);
+    event.Set(kKeyEventResult, EventResultToString(event_result));
+    event.Set(kKeyClickedThrough, event_result == EventResult::BYPASSED);
     if (!content_transfer_method.empty()) {
       event.Set(kKeyContentTransferMethod, content_transfer_method);
     }
 
     reporting_client_->ReportEventWithTimestampDeprecated(
-        enterprise_connectors::kKeyUnscannedFileEvent,
-        std::move(settings.value()), std::move(event), base::Time::Now(),
+        kKeyUnscannedFileEvent, std::move(settings.value()), std::move(event),
+        base::Time::Now(),
         /*include_profile_user_name=*/true);
   }
 }
@@ -474,10 +464,10 @@
     const std::string& content_transfer_method,
     const std::string& source_email,
     const std::string& content_area_account_email,
-    const enterprise_connectors::ContentAnalysisResponse::Result& result,
+    const ContentAnalysisResponse::Result& result,
     const int64_t content_size,
     const ReferrerChain& referrer_chain,
-    enterprise_connectors::EventResult event_result) {
+    EventResult event_result) {
   if (!IsEventEnabled(kKeySensitiveDataEvent)) {
     return;
   }
@@ -520,13 +510,11 @@
     event.Set(kKeyTrigger, trigger);
 
     if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
-      enterprise_connectors::AddReferrerChainToEvent(referrer_chain, event);
+      AddReferrerChainToEvent(referrer_chain, event);
     }
 
-    event.Set(kKeyEventResult,
-              enterprise_connectors::EventResultToString(event_result));
-    event.Set(kKeyClickedThrough,
-              event_result == enterprise_connectors::EventResult::BYPASSED);
+    event.Set(kKeyEventResult, EventResultToString(event_result));
+    event.Set(kKeyClickedThrough, event_result == EventResult::BYPASSED);
     event.Set(kKeyScanId, scan_id);
 
     if (!content_transfer_method.empty()) {
@@ -542,8 +530,8 @@
     AddAnalysisConnectorVerdictToEvent(result, event);
 
     reporting_client_->ReportEventWithTimestampDeprecated(
-        enterprise_connectors::kKeySensitiveDataEvent,
-        std::move(settings.value()), std::move(event), base::Time::Now(),
+        kKeySensitiveDataEvent, std::move(settings.value()), std::move(event),
+        base::Time::Now(),
         /*include_profile_user_name=*/true);
   }
 }
@@ -560,7 +548,7 @@
     const std::string& trigger,
     const int64_t content_size,
     const ReferrerChain& referrer_chain,
-    enterprise_connectors::EventResult event_result,
+    EventResult event_result,
     const std::string& scan_id,
     const std::string& content_transfer_method) {
   if (!IsEventEnabled(kKeyDangerousDownloadEvent)) {
@@ -587,12 +575,10 @@
   }
   event.Set(kKeyTrigger, trigger);
   if (base::FeatureList::IsEnabled(safe_browsing::kEnhancedFieldsForSecOps)) {
-    enterprise_connectors::AddReferrerChainToEvent(referrer_chain, event);
+    AddReferrerChainToEvent(referrer_chain, event);
   }
-  event.Set(kKeyEventResult,
-            enterprise_connectors::EventResultToString(event_result));
-  event.Set(kKeyClickedThrough,
-            event_result == enterprise_connectors::EventResult::BYPASSED);
+  event.Set(kKeyEventResult, EventResultToString(event_result));
+  event.Set(kKeyClickedThrough, event_result == EventResult::BYPASSED);
   // The scan ID can be empty when the reported dangerous download is from a
   // Safe Browsing verdict.
   if (!scan_id.empty()) {
@@ -603,8 +589,8 @@
   }
 
   reporting_client_->ReportEventWithTimestampDeprecated(
-      enterprise_connectors::kKeyDangerousDownloadEvent,
-      std::move(settings.value()), std::move(event), base::Time::Now(),
+      kKeyDangerousDownloadEvent, std::move(settings.value()), std::move(event),
+      base::Time::Now(),
       /*include_profile_user_name=*/true);
 }
 
@@ -621,10 +607,10 @@
     const std::string& content_transfer_method,
     const std::string& source_email,
     const std::string& content_area_account_email,
-    const enterprise_connectors::ContentAnalysisResponse::Result& result,
+    const ContentAnalysisResponse::Result& result,
     const int64_t content_size,
     const ReferrerChain& referrer_chain,
-    enterprise_connectors::EventResult event_result) {
+    EventResult event_result) {
   if (result.tag() == "malware") {
     DCHECK_EQ(1, result.triggered_rules().size());
     OnDangerousDeepScanningResult(
diff --git a/components/enterprise/connectors/core/reporting_utils.cc b/components/enterprise/connectors/core/reporting_utils.cc
index 356e8f6f..b6c1c23 100644
--- a/components/enterprise/connectors/core/reporting_utils.cc
+++ b/components/enterprise/connectors/core/reporting_utils.cc
@@ -252,7 +252,7 @@
 }
 
 std::unique_ptr<url_matcher::URLMatcher> CreateURLMatcherForOptInEvent(
-    const enterprise_connectors::ReportingSettings& settings,
+    const ReportingSettings& settings,
     const char* event_type) {
   const auto& it = settings.enabled_opt_in_events.find(event_type);
   if (it == settings.enabled_opt_in_events.end()) {
@@ -338,7 +338,7 @@
 std::optional<proto::PasswordBreachEvent> GetPasswordBreachEvent(
     const std::string& trigger,
     const std::vector<std::pair<GURL, std::u16string>>& identities,
-    const enterprise_connectors::ReportingSettings& settings,
+    const ReportingSettings& settings,
     const std::string& profile_identifier,
     const std::string& profile_username) {
   std::unique_ptr<url_matcher::URLMatcher> matcher =
@@ -466,8 +466,7 @@
   proto::UrlFilteringInterstitialEvent event;
   event.set_url(url.spec());
   EventResult event_result = GetEventResultFromThreatType(threat_type);
-  event.set_clicked_through(event_result ==
-                            enterprise_connectors::EventResult::BYPASSED);
+  event.set_clicked_through(event_result == EventResult::BYPASSED);
   if (!threat_type.empty()) {
     event.set_threat_type(ConvertThreatTypeToProto(threat_type));
   }
@@ -556,8 +555,7 @@
   }
 
   event.set_event_result(GetEventResult(event_result));
-  event.set_clicked_through(event_result ==
-                            enterprise_connectors::EventResult::BYPASSED);
+  event.set_clicked_through(event_result == EventResult::BYPASSED);
 
   return event;
 }
@@ -629,8 +627,7 @@
   }
 
   event.set_event_result(GetEventResult(event_result));
-  event.set_clicked_through(event_result ==
-                            enterprise_connectors::EventResult::BYPASSED);
+  event.set_clicked_through(event_result == EventResult::BYPASSED);
 
   return event;
 }
diff --git a/components/enterprise/connectors/core/reporting_utils.h b/components/enterprise/connectors/core/reporting_utils.h
index e402b2ba..5086939 100644
--- a/components/enterprise/connectors/core/reporting_utils.h
+++ b/components/enterprise/connectors/core/reporting_utils.h
@@ -51,7 +51,7 @@
 // in the opt-in events field and the URL it relates to matches at least one of
 // the event type's filters.
 std::unique_ptr<url_matcher::URLMatcher> CreateURLMatcherForOptInEvent(
-    const enterprise_connectors::ReportingSettings& settings,
+    const ReportingSettings& settings,
     const char* event_type);
 
 // PasswordBreachEvent could be empty if none of the `identities` matched a
@@ -60,7 +60,7 @@
 GetPasswordBreachEvent(
     const std::string& trigger,
     const std::vector<std::pair<GURL, std::u16string>>& identities,
-    const enterprise_connectors::ReportingSettings& settings,
+    const ReportingSettings& settings,
     const std::string& profile_identifier,
     const std::string& profile_username);
 
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
index b2ad3d2a..0e9e1af 100644
--- a/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
+++ b/components/facilitated_payments/core/browser/pix_account_linking_manager.cc
@@ -8,6 +8,8 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/functional/bind.h"
 #include "base/notreached.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/time/time.h"
 #include "components/autofill/core/browser/data_manager/payments/payments_data_manager.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/facilitated_payments/core/browser/facilitated_payments_client.h"
@@ -16,6 +18,9 @@
 
 namespace payments::facilitated {
 
+// Delay before showing the account linking prompt.
+constexpr base::TimeDelta kShowPromptDelay = base::Seconds(3);
+
 PixAccountLinkingManager::PixAccountLinkingManager(
     FacilitatedPaymentsClient* client)
     : client_(CHECK_DEREF(client)) {}
@@ -114,6 +119,15 @@
     return;
   }
 
+  base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(
+          &PixAccountLinkingManager::ShowPixAccountLinkingPromptAfterDelay,
+          weak_ptr_factory_.GetWeakPtr()),
+      kShowPromptDelay);
+}
+
+void PixAccountLinkingManager::ShowPixAccountLinkingPromptAfterDelay() {
   client_->SetUiEventListener(
       base::BindRepeating(&PixAccountLinkingManager::OnUiScreenEvent,
                           weak_ptr_factory_.GetWeakPtr()));
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager.h b/components/facilitated_payments/core/browser/pix_account_linking_manager.h
index 376bd2e..7895a8c5 100644
--- a/components/facilitated_payments/core/browser/pix_account_linking_manager.h
+++ b/components/facilitated_payments/core/browser/pix_account_linking_manager.h
@@ -42,6 +42,10 @@
   // showing the Pix account linking prompt if the user is eligible.
   void ShowPixAccountLinkingPromptIfEligible();
 
+  // Shows the Pix account linking prompt to user after the predefined wait
+  // time.
+  void ShowPixAccountLinkingPromptAfterDelay();
+
   // Sets the internal UI state and triggers dismissal.
   void DismissPrompt();
 
diff --git a/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc b/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
index 43e80a17..6d77ea55 100644
--- a/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
+++ b/components/facilitated_payments/core/browser/pix_account_linking_manager_unittest.cc
@@ -111,6 +111,7 @@
   std::unique_ptr<autofill::TestPaymentsDataManager> payments_data_manager_;
   const url::Origin kPixPaymentPageOrigin =
       url::Origin::Create(GURL("https://example.com"));
+  const base::TimeDelta kShowPromptDelay = base::Seconds(3);
 
  private:
   // Order matters here because `manager_` keeps a reference to `client_`.
@@ -124,9 +125,15 @@
 };
 
 TEST_F(PixAccountLinkingManagerTest, SuccessPathShowsPrompt) {
+  // The prompt should not be shown synchronously.
+  EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
+  manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+
+  // Expect the prompt to be shown then.
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt);
 
-  manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  // Fast-forward time by 3 seconds to trigger the delayed task.
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest,
@@ -137,6 +144,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest,
@@ -147,6 +155,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest,
@@ -162,6 +171,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest,
@@ -176,6 +186,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest,
@@ -195,6 +206,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest, TabNotActive_PromptNotShown) {
@@ -204,6 +216,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest, UserNotReturnedToChrome_PromptNotShown) {
@@ -214,6 +227,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest, DifferentOrigin_PromptNotShown) {
@@ -227,6 +241,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 TEST_F(PixAccountLinkingManagerTest, DismissPrompt) {
@@ -236,6 +251,7 @@
 
   // The show method is called so the internal UI state is correctly set.
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().DismissPrompt();
   // This call should not trigger prompt dismissal again.
   test_api().DismissPrompt();
@@ -248,6 +264,7 @@
 
   // The show method is called so the internal UI state is correctly set.
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnAccepted();
 }
 
@@ -261,6 +278,7 @@
 
   // The show method is called so the internal UI state is correctly set.
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnAccepted();
 }
 
@@ -273,6 +291,7 @@
 
   // The show method is called so the internal UI state is correctly set.
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnDeclined();
 
   // Verify that declining the prompt disables the account linking user pref.
@@ -282,6 +301,7 @@
 
 TEST_F(PixAccountLinkingManagerTest, Reset_PromptShowing_TriggersDismissal) {
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 
   EXPECT_CALL(client(), DismissPrompt());
 
@@ -313,6 +333,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   // Reset() is called before the user returns to Chrome. This should invalidate
   // the weak pointer for the callback.
   test_api().Reset();
@@ -325,6 +346,7 @@
   base::HistogramTester histogram_tester;
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnAccepted();
 
   histogram_tester.ExpectUniqueSample(
@@ -337,6 +359,7 @@
   base::HistogramTester histogram_tester;
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnUiScreenEvent(UiEvent::kNewScreenShown);
 
   histogram_tester.ExpectUniqueSample(
@@ -349,6 +372,7 @@
   base::HistogramTester histogram_tester;
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnUiScreenEvent(UiEvent::kScreenCouldNotBeShown);
 
   histogram_tester.ExpectUniqueSample(
@@ -364,6 +388,7 @@
   EXPECT_CALL(client(), ShowPixAccountLinkingPrompt).Times(0);
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
 }
 
 class PixAccountLinkingManagerParameterizedTest
@@ -399,6 +424,7 @@
   base::HistogramTester histogram_tester;
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnDeclined();
 
   histogram_tester.ExpectUniqueSample(
@@ -432,6 +458,7 @@
   base::HistogramTester histogram_tester;
 
   manager()->MaybeShowPixAccountLinkingPrompt(kPixPaymentPageOrigin);
+  task_environment_.FastForwardBy(kShowPromptDelay);
   test_api().OnUiScreenEvent(ui_event());
 
   histogram_tester.ExpectUniqueSample(
diff --git a/components/feature_engagement/internal/BUILD.gn b/components/feature_engagement/internal/BUILD.gn
index 7a04712..14b7fb9e 100644
--- a/components/feature_engagement/internal/BUILD.gn
+++ b/components/feature_engagement/internal/BUILD.gn
@@ -155,6 +155,10 @@
     "//testing/gmock",
     "//testing/gtest",
   ]
+
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
 
 if (is_android) {
diff --git a/components/global_media_controls/public/format_duration.cc b/components/global_media_controls/public/format_duration.cc
index d300f48..e6f892b 100644
--- a/components/global_media_controls/public/format_duration.cc
+++ b/components/global_media_controls/public/format_duration.cc
@@ -42,7 +42,7 @@
   std::vector<icu::Measure> measures;
 
   const int64_t total_seconds =
-      base::ClampRound<int64_t>(duration.InSecondsF());
+      base::ClampFloor<int64_t>(duration.InSecondsF());
   const int64_t hours = total_seconds / base::Time::kSecondsPerHour;
   if (hours != 0) {
     measures.emplace_back(hours, icu::MeasureUnit::createHour(status), status);
diff --git a/components/global_media_controls/public/format_duration_unittest.cc b/components/global_media_controls/public/format_duration_unittest.cc
index 89c305e..e15abbd5 100644
--- a/components/global_media_controls/public/format_duration_unittest.cc
+++ b/components/global_media_controls/public/format_duration_unittest.cc
@@ -33,4 +33,11 @@
   EXPECT_EQ(u"0:00", GetFormattedDuration(zero_duration));
 }
 
+TEST_F(FormatDurationTest, FormatNonIntegerTimes) {
+  // `GetFormattedDuration()` should always round to the floor.
+  EXPECT_EQ(u"0:05", GetFormattedDuration(base::Milliseconds(5200)));
+  EXPECT_EQ(u"0:13", GetFormattedDuration(base::Milliseconds(13500)));
+  EXPECT_EQ(u"0:19", GetFormattedDuration(base::Milliseconds(19999)));
+}
+
 }  // namespace global_media_controls
diff --git a/components/invalidation/invalidation_listener.cc b/components/invalidation/invalidation_listener.cc
index 710e0c3..aaa18e7 100644
--- a/components/invalidation/invalidation_listener.cc
+++ b/components/invalidation/invalidation_listener.cc
@@ -7,15 +7,25 @@
 #include <stdint.h>
 
 #include <memory>
+#include <utility>
 
 #include "components/gcm_driver/instance_id/instance_id_driver.h"
 #include "components/invalidation/invalidation_listener_impl.h"
 
 namespace invalidation {
 
-std::string DirectInvalidation::type() const {
-  return invalidation::Invalidation::topic();
-}
+DirectInvalidation::DirectInvalidation(std::string type,
+                                       int64_t version,
+                                       std::string payload)
+    : type_(std::move(type)), version_(version), payload_(std::move(payload)) {}
+
+DirectInvalidation::DirectInvalidation(const DirectInvalidation& other) =
+    default;
+
+DirectInvalidation& DirectInvalidation::operator=(
+    const DirectInvalidation& other) = default;
+
+DirectInvalidation::~DirectInvalidation() = default;
 
 base::Time DirectInvalidation::issue_timestamp() const {
   return base::Time::UnixEpoch() + base::Microseconds(version());
diff --git a/components/invalidation/invalidation_listener.h b/components/invalidation/invalidation_listener.h
index 9ebe450..cb7161c 100644
--- a/components/invalidation/invalidation_listener.h
+++ b/components/invalidation/invalidation_listener.h
@@ -12,7 +12,6 @@
 
 #include "base/observer_list_types.h"
 #include "base/time/time.h"
-#include "components/invalidation/public/invalidation.h"
 
 namespace gcm {
 class GCMDriver;
@@ -24,19 +23,32 @@
 
 namespace invalidation {
 
-// For the migration from topic based (Fandango) invalidations to direct
-// message invalidations, this is a thin wrapper around the topic based
-// invalidations. The only reason for having this is to provide the `type`
-// method in the interface (as opposed to using the `topic` method).
-// TODO(b/350013667) Once we fully migrated to direct message
-// invalidations, we can delete `invalidation::Invalidation` and rename this to
-// Invalidation.
-class DirectInvalidation : public invalidation::Invalidation {
+// An invalidation message.
+// Represents a call for action with a specific `type()` and an optional `payload()`.
+class DirectInvalidation {
  public:
-  using invalidation::Invalidation::Invalidation;
+  DirectInvalidation(std::string type, int64_t version, std::string payload);
+  DirectInvalidation(const DirectInvalidation& other);
+  DirectInvalidation& operator=(const DirectInvalidation& other);
+  ~DirectInvalidation();
 
-  std::string type() const;
+  // Compares two invalidations.
+  constexpr bool operator==(const DirectInvalidation&) const = default;
+
+  const std::string& type() const { return type_; }
+  int64_t version() const { return version_; }
   base::Time issue_timestamp() const;
+  const std::string& payload() const { return payload_; }
+
+ private:
+  // The type to which this invalidation belongs.
+  std::string type_;
+
+  // The version number of this invalidation.
+  int64_t version_;
+
+  // The payload associated with this invalidation.
+  std::string payload_;
 };
 
 // Interface to handle obtained registration tokens.
diff --git a/components/ip_protection/android/blind_sign_message_android_impl.cc b/components/ip_protection/android/blind_sign_message_android_impl.cc
index 7c60703c..a129828f 100644
--- a/components/ip_protection/android/blind_sign_message_android_impl.cc
+++ b/components/ip_protection/android/blind_sign_message_android_impl.cc
@@ -145,6 +145,7 @@
               /*start_time=*/base::TimeTicks::Now())));
       break;
     }
+    case quiche::BlindSignMessageRequestType::kAttestAndSign:
     case quiche::BlindSignMessageRequestType::kUnknown:
       NOTREACHED();
   }
diff --git a/components/ip_protection/common/ip_protection_config_http.cc b/components/ip_protection/common/ip_protection_config_http.cc
index a6b2958..f09d2112 100644
--- a/components/ip_protection/common/ip_protection_config_http.cc
+++ b/components/ip_protection/common/ip_protection_config_http.cc
@@ -92,6 +92,7 @@
     case quiche::BlindSignMessageRequestType::kAuthAndSign:
       replacements.SetPathStr(ip_protection_server_get_tokens_path_);
       break;
+    case quiche::BlindSignMessageRequestType::kAttestAndSign:
     case quiche::BlindSignMessageRequestType::kUnknown:
       NOTREACHED();
   }
diff --git a/components/ip_protection/common/mock_blind_sign_auth.cc b/components/ip_protection/common/mock_blind_sign_auth.cc
index aab36f9..c4f251d 100644
--- a/components/ip_protection/common/mock_blind_sign_auth.cc
+++ b/components/ip_protection/common/mock_blind_sign_auth.cc
@@ -46,16 +46,8 @@
 void MockBlindSignAuth::GetAttestationTokens(
     int num_tokens,
     quiche::ProxyLayer layer,
-    quiche::AttestationDataCallback callback) {
-  NOTREACHED() << "Not implemented";
-}
-
-void MockBlindSignAuth::AttestAndSign(
-    int num_tokens,
-    quiche::ProxyLayer layer,
-    std::string attestation_data,
-    std::optional<std::string> token_challenge,
-    quiche::SignedTokenCallback callback) {
+    quiche::AttestationDataCallback attestation_data_callback,
+    quiche::SignedTokenCallback token_callback) {
   NOTREACHED() << "Not implemented";
 }
 
diff --git a/components/ip_protection/common/mock_blind_sign_auth.h b/components/ip_protection/common/mock_blind_sign_auth.h
index 91c9a6e..8a553462 100644
--- a/components/ip_protection/common/mock_blind_sign_auth.h
+++ b/components/ip_protection/common/mock_blind_sign_auth.h
@@ -31,15 +31,11 @@
                  quiche::BlindSignAuthServiceType /*service_type*/,
                  quiche::SignedTokenCallback callback) override;
 
-  void GetAttestationTokens(int num_tokens,
-                            quiche::ProxyLayer layer,
-                            quiche::AttestationDataCallback callback) override;
-
-  void AttestAndSign(int num_tokens,
-                     quiche::ProxyLayer layer,
-                     std::string attestation_data,
-                     std::optional<std::string> token_challenge,
-                     quiche::SignedTokenCallback callback) override;
+  void GetAttestationTokens(
+      int num_tokens,
+      quiche::ProxyLayer layer,
+      quiche::AttestationDataCallback attestation_data_callback,
+      quiche::SignedTokenCallback token_callback) override;
 
   void set_tokens(std::vector<quiche::BlindSignToken> tokens) {
     tokens_ = std::move(tokens);
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index a308060..95574c75 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -576,6 +576,9 @@
 constexpr base::FeatureParam<bool> kOpenAimInSidePanel{
     &kLensSearchAimM3, "open-aim-in-side-panel", true};
 
+constexpr base::FeatureParam<bool> kAimSearchboxEnabled{
+    &kLensSearchAimM3, "aim-searchbox-enabled", true};
+
 const base::FeatureParam<int> kLensOverlayEntrypointLabelAltId{
     &kLensOverlayEntrypointLabelAlt, "id", 0};
 
@@ -1080,6 +1083,11 @@
          kOpenAimInSidePanel.Get();
 }
 
+bool GetAimSearchboxEnabled() {
+  return base::FeatureList::IsEnabled(kLensSearchAimM3) &&
+         kAimSearchboxEnabled.Get();
+}
+
 bool ShouldUseAltLoadingHintWeb() {
   return kUseAltLoadingHintWeb.Get();
 }
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 4e8200f..229eaf5 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -835,6 +835,10 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern bool ShouldShowAimInSidePanel();
 
+// Whether the AIM searchbox is enabled.
+COMPONENT_EXPORT(LENS_FEATURES)
+extern bool GetAimSearchboxEnabled();
+
 // Whether to use the alt loading hint when overlay is opened on web pages.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern bool ShouldUseAltLoadingHintWeb();
diff --git a/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouterClient.java b/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouterClient.java
index 7d17823..a5bb5310 100644
--- a/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouterClient.java
+++ b/components/media_router/browser/android/java/src/org/chromium/components/media_router/MediaRouterClient.java
@@ -68,9 +68,9 @@
     /**
      * @param initiator the web contents that initiated the request.
      * @return a {@link FragmentManager} suitable for displaying a media router {@link
-     *         DialogFragment} in.
+     *     DialogFragment} in.
      */
-    public abstract FragmentManager getSupportFragmentManager(WebContents initiator);
+    public abstract @Nullable FragmentManager getSupportFragmentManager(WebContents initiator);
 
     /** Runs deferredTask on the main thread when the main thread is idle. */
     public abstract void addDeferredTask(Runnable deferredTask);
diff --git a/components/omnibox/browser/autocomplete_result_android.cc b/components/omnibox/browser/autocomplete_result_android.cc
index 68665c6..304ad6ed 100644
--- a/components/omnibox/browser/autocomplete_result_android.cc
+++ b/components/omnibox/browser/autocomplete_result_android.cc
@@ -134,7 +134,7 @@
 ScopedJavaLocalRef<jobjectArray> AutocompleteResult::BuildJavaMatches(
     JNIEnv* env) const {
   jclass clazz = AutocompleteMatch::GetClazz(env);
-  ScopedJavaLocalRef<jobjectArray> j_matches(
+  auto j_matches = ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(matches_.size(), clazz, nullptr));
   base::android::CheckException(env);
 
diff --git a/components/omnibox/composebox/composebox_query_controller.cc b/components/omnibox/composebox/composebox_query_controller.cc
index 97b3f9f..6052ff8 100644
--- a/components/omnibox/composebox/composebox_query_controller.cc
+++ b/components/omnibox/composebox/composebox_query_controller.cc
@@ -208,11 +208,13 @@
     const std::unique_ptr<FileInfo>& last_file = active_files_.rbegin()->second;
     if (IsValidFileUploadStatusForMultimodalRequest(
             last_file->upload_status_)) {
+      std::unique_ptr<lens::LensOverlayRequestId> request_id =
+          request_id_generator_.GetNextRequestId(
+              lens::RequestIdUpdateMode::kSearchUrl);
+      request_id->set_media_type(last_file->request_id_->media_type());
       return GetUrlForMultimodalAim(
           template_url_service_, kEntrypointParameterValue, query_start_time,
-          cluster_info_->search_session_id(),
-          request_id_generator_.GetNextRequestId(
-              lens::RequestIdUpdateMode::kSearchUrl),
+          cluster_info_->search_session_id(), std::move(request_id),
           last_file->mime_type_,
           send_lns_surface_ ? kLnsSurfaceParameterValue : std::string(),
           base::UTF8ToUTF16(query_text));
@@ -254,6 +256,10 @@
       current_file_info.mime_type_ == lens::MimeType::kPdf
           ? lens::RequestIdUpdateMode::kPageContentRequest
           : lens::RequestIdUpdateMode::kFullImageRequest);
+  current_file_info.request_id_->set_media_type(
+      current_file_info.mime_type_ == lens::MimeType::kPdf
+          ? lens::LensOverlayRequestId::MEDIA_TYPE_PDF
+          : lens::LensOverlayRequestId::MEDIA_TYPE_DEFAULT_IMAGE);
 
   // Preparing for the file upload request requires multiple async flows to
   // complete before the request is ready to be send to the server. Start the
diff --git a/components/omnibox/composebox/composebox_query_controller_unittest.cc b/components/omnibox/composebox/composebox_query_controller_unittest.cc
index 72bc10a..d185f1a 100644
--- a/components/omnibox/composebox/composebox_query_controller_unittest.cc
+++ b/components/omnibox/composebox/composebox_query_controller_unittest.cc
@@ -8,6 +8,7 @@
 #include <optional>
 #include <string>
 
+#include "base/base64url.h"
 #include "base/test/bind.h"
 #include "base/test/repeating_test_future.h"
 #include "base/test/task_environment.h"
@@ -228,6 +229,24 @@
   }
 #endif  // !BUILDFLAG(IS_IOS)
 
+  lens::LensOverlayRequestId DecodeRequestIdFromVsrid(std::string vsrid_param) {
+    std::string serialized_proto;
+    EXPECT_TRUE(base::Base64UrlDecode(
+        vsrid_param, base::Base64UrlDecodePolicy::DISALLOW_PADDING,
+        &serialized_proto));
+    lens::LensOverlayRequestId proto;
+    EXPECT_TRUE(proto.ParseFromString(serialized_proto));
+    return proto;
+  }
+
+  lens::LensOverlayRequestId GetRequestIdFromUrl(std::string url_string) {
+    GURL url = GURL(url_string);
+    std::string vsrid_param;
+    EXPECT_TRUE(
+        net::GetValueForKeyInQuery(url, kRequestIdParameterKey, &vsrid_param));
+    return DecodeRequestIdFromVsrid(vsrid_param);
+  }
+
  protected:
   signin::IdentityTestEnvironment* identity_test_env() {
     return &identity_test_env_;
@@ -421,6 +440,13 @@
                 .image_encode_data()
                 .encoded_image_size_bytes(),
             360);
+  EXPECT_EQ(controller()
+                .last_sent_file_upload_request()
+                ->objects_request()
+                .request_context()
+                .request_id()
+                .media_type(),
+            lens::LensOverlayRequestId::MEDIA_TYPE_DEFAULT_IMAGE);
   // Check that the vsrid matches that for an image upload.
   EXPECT_EQ(controller()
                 .GetFileInfo(file_token)
@@ -546,6 +572,13 @@
                 .request_id()
                 .long_context_id(),
             1);
+  EXPECT_EQ(controller()
+                .last_sent_file_upload_request()
+                ->objects_request()
+                .request_context()
+                .request_id()
+                .media_type(),
+            lens::LensOverlayRequestId::MEDIA_TYPE_PDF);
   // Check that the routing info is in the vsrid.
   EXPECT_EQ(controller()
                 .GetFileInfo(file_token)
@@ -934,6 +967,8 @@
   EXPECT_TRUE(net::GetValueForKeyInQuery(aim_url, kRequestIdParameterKey,
                                          &vsrid_value));
   EXPECT_FALSE(vsrid_value.empty());
+  EXPECT_EQ(lens::LensOverlayRequestId::MEDIA_TYPE_PDF,
+            DecodeRequestIdFromVsrid(vsrid_value).media_type());
 
   // Assert: Visual input type is set to pdf for multimodal pdf queries.
   std::string vit_value;
@@ -959,6 +994,66 @@
   EXPECT_EQ(pqsubts_value, "1000");
 }
 
+#if !BUILDFLAG(IS_IOS)
+TEST_F(ComposeboxQueryControllerTest, QuerySubmittedWithUploadedImage) {
+  // Act: Start the session.
+  controller().NotifySessionStarted();
+
+  // Assert: Validate cluster info request and state changes.
+  WaitForClusterInfo();
+
+  // Act: Start the file upload flow.
+  const base::UnguessableToken file_token = base::UnguessableToken::Create();
+  std::vector<uint8_t> image_bytes = CreateJPGBytes(100, 100);
+  composebox::ImageEncodingOptions image_options{.max_size = 1000000,
+                                                 .max_height = 1000,
+                                                 .max_width = 1000,
+                                                 .compression_quality = 30};
+  StartImageFileUploadFlow(
+      file_token,
+      /*file_data=*/base::MakeRefCounted<base::RefCountedBytes>(image_bytes),
+      image_options);
+
+  // Assert: Validate file upload request and status changes.
+  WaitForFileUpload(file_token);
+
+  // Act: Create the destination URL for the query. The destination URL can
+  // only be created after the cluster info is received.
+  GURL aim_url = controller().CreateAimUrl("hello", kTestQueryStartTime);
+
+  // Assert: Lens request id is NOT added to multimodal pdf queries.
+  std::string vsrid_value;
+  EXPECT_TRUE(net::GetValueForKeyInQuery(aim_url, kRequestIdParameterKey,
+                                         &vsrid_value));
+  EXPECT_FALSE(vsrid_value.empty());
+  EXPECT_EQ(lens::LensOverlayRequestId::MEDIA_TYPE_DEFAULT_IMAGE,
+            DecodeRequestIdFromVsrid(vsrid_value).media_type());
+
+  // Assert: Visual input type is set to img for multimodal image queries.
+  std::string vit_value;
+  EXPECT_TRUE(net::GetValueForKeyInQuery(aim_url, kVisualInputTypeParameterKey,
+                                         &vit_value));
+  EXPECT_EQ(vit_value, "img");
+
+  // Assert: Gsession id is added to multimodal pdf queries.
+  std::string gsession_id_value;
+  EXPECT_TRUE(net::GetValueForKeyInQuery(aim_url, kSessionIdQueryParameterKey,
+                                         &gsession_id_value));
+  EXPECT_EQ(kTestSearchSessionId, gsession_id_value);
+
+  // Check that the timestamps are attached to the url.
+  std::string qsubts_value;
+  EXPECT_TRUE(net::GetValueForKeyInQuery(
+      aim_url, kQuerySubmissionTimeQueryParameter, &qsubts_value));
+
+  std::string pqsubts_value;
+  EXPECT_TRUE(net::GetValueForKeyInQuery(
+      aim_url, kUserPerceivedQuerySubmissionTimeQueryParameter,
+      &pqsubts_value));
+  EXPECT_EQ(pqsubts_value, "1000");
+}
+#endif  // !BUILDFLAG(IS_IOS)
+
 TEST_F(ComposeboxQueryControllerTest,
        QuerySubmittedWithUploadedPdfButInvalidClusterInfoIsUnimodal) {
   // Enable cluster info TTL.
diff --git a/components/optimization_guide/content/browser/DEPS b/components/optimization_guide/content/browser/DEPS
index 9a8c2505..e05e929 100644
--- a/components/optimization_guide/content/browser/DEPS
+++ b/components/optimization_guide/content/browser/DEPS
@@ -16,6 +16,7 @@
     "+content/shell",
     "+components/network_session_configurator/common/network_switches.h",
     "+components/ukm/test_ukm_recorder.h",
+    "+services/media_session/public/cpp/test/mock_media_session.h",
     "+services/metrics/public/cpp/ukm_builders.h",
   ],
   "frame_metadata_observer_browsertest\.cc": [
diff --git a/components/optimization_guide/content/browser/page_content_proto_provider.cc b/components/optimization_guide/content/browser/page_content_proto_provider.cc
index 992b2371..e23e2fe 100644
--- a/components/optimization_guide/content/browser/page_content_proto_provider.cc
+++ b/components/optimization_guide/content/browser/page_content_proto_provider.cc
@@ -14,6 +14,7 @@
 #include "base/timer/elapsed_timer.h"
 #include "components/optimization_guide/content/browser/page_content_proto_util.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
+#include "content/public/browser/media_session.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
@@ -69,6 +70,83 @@
   return new_options;
 }
 
+// Validate that the media session has all the required data before proceeding
+// to create media data.
+bool ValidateMediaSession(
+    const media_session::mojom::MediaSessionInfoPtr& media_session_info,
+    const std::optional<media_session::MediaPosition>& media_position) {
+  return media_session_info && media_session_info->audio_video_states &&
+         !media_session_info->audio_video_states->empty() && media_position &&
+         !media_position->duration().is_zero();
+}
+
+// Find the media data from the web contents for the given render frame host if
+// there is an active media session in the web page, otherwise return nullopt.
+// TODO(crbug.com/409427125): Add transcripts from the glic media integration.
+// TODO(crbug.com/409427125): Add last_updated_time for current_position so that
+// we can calculate a more precise position.
+std::optional<optimization_guide::proto::MediaData> ComputeMediaData(
+    content::RenderFrameHost* render_frame_host) {
+  CHECK(render_frame_host);
+  if (!base::FeatureList::IsEnabled(
+          features::kAnnotatedPageContentWithMediaData)) {
+    return std::nullopt;
+  }
+
+  auto* web_contents =
+      content::WebContents::FromRenderFrameHost(render_frame_host);
+  if (!web_contents) {
+    return std::nullopt;
+  }
+
+  auto* media_session = content::MediaSession::GetIfExists(web_contents);
+  if (!media_session ||
+      (render_frame_host != media_session->GetRoutedFrame())) {
+    return std::nullopt;
+  }
+
+  auto media_session_info = media_session->GetMediaSessionInfoSync();
+  auto media_position = media_session->GetMediaSessionPosition();
+  if (!ValidateMediaSession(media_session_info, media_position)) {
+    return std::nullopt;
+  }
+
+  optimization_guide::proto::MediaData media_data;
+  media_data.set_is_playing(media_session_info->playback_state ==
+                            media_session::mojom::MediaPlaybackState::kPlaying);
+  media_data.set_duration_milliseconds(
+      media_position->duration().InMillisecondsRoundedUp());
+  media_data.set_current_position_milliseconds(
+      media_position->GetPosition().InMillisecondsRoundedUp());
+
+  // Find the media data type via the audio video states in the media session
+  // info. If there are multiple media in the frame which is rare, select the
+  // first media for simplicity.
+  auto& first_state = media_session_info->audio_video_states->at(0);
+  switch (first_state) {
+    case media_session::mojom::MediaAudioVideoState::kAudioOnly:
+      media_data.set_media_data_type(
+          optimization_guide::proto::MediaDataType::MEDIA_DATA_TYPE_AUDIO);
+      break;
+    case media_session::mojom::MediaAudioVideoState::kAudioVideo:
+    case media_session::mojom::MediaAudioVideoState::kVideoOnly:
+      media_data.set_media_data_type(
+          optimization_guide::proto::MediaDataType::MEDIA_DATA_TYPE_VIDEO);
+      break;
+    case media_session::mojom::MediaAudioVideoState::kDeprecatedUnknown:
+      NOTREACHED();
+  }
+
+  // Set the media metadata.
+  const media_session::MediaMetadata& media_metadata =
+      media_session->GetMediaSessionMetadata();
+  media_data.set_title(base::UTF16ToUTF8(media_metadata.title));
+  media_data.set_artist(base::UTF16ToUTF8(media_metadata.artist));
+  media_data.set_album(base::UTF16ToUTF8(media_metadata.album));
+
+  return media_data;
+}
+
 std::optional<optimization_guide::RenderFrameInfo> GetRenderFrameInfo(
     int child_process_id,
     blink::FrameToken frame_token) {
@@ -104,6 +182,7 @@
   //    convey that.
   render_frame_info.source_origin = render_frame_host->GetLastCommittedOrigin();
   render_frame_info.url = render_frame_host->GetLastCommittedURL();
+  render_frame_info.media_data = ComputeMediaData(render_frame_host);
   return render_frame_info;
 }
 
diff --git a/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc b/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc
index 7d5698a..d52cdd8 100644
--- a/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc
+++ b/components/optimization_guide/content/browser/page_content_proto_provider_browsertest.cc
@@ -10,6 +10,7 @@
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/ukm/test_ukm_recorder.h"
+#include "content/public/browser/media_session.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -17,9 +18,11 @@
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/fenced_frame_test_util.h"
+#include "content/public/test/media_start_stop_observer.h"
 #include "content/shell/browser/shell.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/request_handler_util.h"
+#include "services/media_session/public/cpp/test/mock_media_session.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "third_party/blink/public/common/features_generated.h"
 #include "ui/display/display_switches.h"
@@ -1173,6 +1176,136 @@
   EXPECT_TRUE(tool.annotations().read_only());
 }
 
+class PageContentProtoProviderBrowserTestMediaData
+    : public PageContentProtoProviderBrowserTest {
+ public:
+  PageContentProtoProviderBrowserTestMediaData()
+      : features_(features::kAnnotatedPageContentWithMediaData) {}
+
+  void WaitForMediaPlaybackStart(content::WebContents* web_contents) {
+    content::MediaStartStopObserver observer(
+        web_contents, content::MediaStartStopObserver::Type::kStart);
+    ASSERT_EQ(base::Value(), content::EvalJs(web_contents, "play()"));
+    observer.Wait();
+  }
+
+  void WaitForMediaPlaybackStop(content::WebContents* web_contents) {
+    content::MediaStartStopObserver observer(
+        web_contents, content::MediaStartStopObserver::Type::kStop);
+    ASSERT_EQ(base::Value(), content::EvalJs(web_contents, "pause()"));
+    observer.Wait();
+  }
+
+  media_session::MediaMetadata GetExpectedMetadata() {
+    media_session::MediaMetadata metadata;
+    metadata.title = u"test title";
+    metadata.artist = u"test artist";
+    metadata.album = u"test album";
+    metadata.source_title = base::ASCIIToUTF16(base::StringPrintf(
+        "%s:%u", https_server()->GetIPLiteralString().c_str(),
+        https_server()->port()));
+    return metadata;
+  }
+
+ private:
+  base::test::ScopedFeatureList features_;
+};
+
+IN_PROC_BROWSER_TEST_F(PageContentProtoProviderBrowserTestMediaData,
+                       NoDataForEmptyDuration) {
+  LoadPage(https_server()->GetURL("/media_data/video.html"));
+  EXPECT_FALSE(page_content().main_frame_data().has_media_data());
+}
+
+IN_PROC_BROWSER_TEST_F(PageContentProtoProviderBrowserTestMediaData,
+                       VideoInMainFrame) {
+  media_session::test::MockMediaSessionMojoObserver observer(
+      *content::MediaSession::Get(web_contents()));
+  LoadPage(https_server()->GetURL("/media_data/video.html"), nullptr);
+
+  WaitForMediaPlaybackStart(web_contents());
+  ASSERT_EQ(base::Value(), content::EvalJs(web_contents(), "setupPosition()"));
+  media_session::MediaPosition position(
+      /*playback_rate=*/1.0, /*duration=*/base::Seconds(10),
+      /*position=*/base::Seconds(5), /*end_of_media=*/false);
+  observer.WaitForExpectedPosition(position);
+  LoadData();
+
+  // Check that the main frame has media data.
+  EXPECT_TRUE(page_content().main_frame_data().has_media_data());
+  const auto& media_data = page_content().main_frame_data().media_data();
+  EXPECT_EQ(media_data.media_data_type(),
+            optimization_guide::proto::MediaDataType::MEDIA_DATA_TYPE_VIDEO);
+  EXPECT_EQ(media_data.duration_milliseconds(), 10000);
+  EXPECT_TRUE(media_data.is_playing());
+
+  // The metadata title is default to the page title if not set.
+  EXPECT_EQ(media_data.title(), "Test page showing a video");
+}
+
+IN_PROC_BROWSER_TEST_F(PageContentProtoProviderBrowserTestMediaData,
+                       UpdateVideoInMainFrame) {
+  media_session::test::MockMediaSessionMojoObserver observer(
+      *content::MediaSession::Get(web_contents()));
+  LoadPage(https_server()->GetURL("/media_data/video.html"));
+
+  // Start the media playback to ensure the media player is added to the media
+  // session and then stop playing.
+  WaitForMediaPlaybackStart(web_contents());
+  WaitForMediaPlaybackStop(web_contents());
+
+  // Update the video with media session API calls.
+  ASSERT_EQ(base::Value(), content::EvalJs(web_contents(), "setupMetadata()"));
+  observer.WaitForExpectedMetadata(GetExpectedMetadata());
+  ASSERT_EQ(base::Value(), content::EvalJs(web_contents(), "setupPosition()"));
+  media_session::MediaPosition position(
+      /*playback_rate=*/1.0, /*duration=*/base::Seconds(10),
+      /*position=*/base::Seconds(5), /*end_of_media=*/false);
+  observer.WaitForExpectedPosition(position);
+  LoadData();
+
+  // Check that the main frame has media data with updated fields.
+  EXPECT_TRUE(page_content().main_frame_data().has_media_data());
+  const auto& media_data = page_content().main_frame_data().media_data();
+  EXPECT_EQ(media_data.media_data_type(),
+            optimization_guide::proto::MediaDataType::MEDIA_DATA_TYPE_VIDEO);
+  EXPECT_EQ(media_data.duration_milliseconds(), 10000);
+  EXPECT_FALSE(media_data.is_playing());
+  EXPECT_EQ(media_data.title(), "test title");
+  EXPECT_EQ(media_data.artist(), "test artist");
+  EXPECT_EQ(media_data.album(), "test album");
+}
+
+IN_PROC_BROWSER_TEST_F(PageContentProtoProviderBrowserTestMediaData,
+                       VideoInIframe) {
+  media_session::test::MockMediaSessionMojoObserver observer(
+      *content::MediaSession::Get(web_contents()));
+  LoadPage(https_server()->GetURL("/media_data/video_in_iframe.html"), nullptr);
+  WaitForMediaPlaybackStart(web_contents());
+  ASSERT_EQ(base::Value(), content::EvalJs(web_contents(), "setupPosition()"));
+  media_session::MediaPosition position(
+      /*playback_rate=*/1.0, /*duration=*/base::Seconds(10),
+      /*position=*/base::Seconds(5), /*end_of_media=*/false);
+  observer.WaitForExpectedPosition(position);
+  LoadData();
+
+  EXPECT_FALSE(page_content().main_frame_data().has_media_data());
+
+  // Check that the iframe has media data.
+  EXPECT_EQ(page_content().root_node().children_nodes().size(), 1);
+  const auto& iframe = page_content().root_node().children_nodes()[0];
+  EXPECT_EQ(iframe.content_attributes().attribute_type(),
+            optimization_guide::proto::CONTENT_ATTRIBUTE_IFRAME);
+  const auto& iframe_data = iframe.content_attributes().iframe_data();
+  EXPECT_TRUE(iframe_data.frame_data().has_media_data());
+  const auto& media_data = iframe_data.frame_data().media_data();
+
+  EXPECT_EQ(media_data.media_data_type(),
+            optimization_guide::proto::MediaDataType::MEDIA_DATA_TYPE_VIDEO);
+  EXPECT_EQ(media_data.duration_milliseconds(), 10000);
+  EXPECT_TRUE(media_data.is_playing());
+}
+
 }  // namespace
 
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/content/browser/page_content_proto_util.cc b/components/optimization_guide/content/browser/page_content_proto_util.cc
index 1ff3ed9..9d338d19 100644
--- a/components/optimization_guide/content/browser/page_content_proto_util.cc
+++ b/components/optimization_guide/content/browser/page_content_proto_util.cc
@@ -641,6 +641,10 @@
         mojom_frame_data.contains_paid_content.value());
   }
 
+  if (render_frame_info.media_data) {
+    *proto_frame_data->mutable_media_data() = *render_frame_info.media_data;
+  }
+
   for (const auto& tool : mojom_frame_data.script_tools) {
     ConvertScriptTool(*tool, proto_frame_data->add_script_tools());
   }
@@ -721,7 +725,6 @@
       if (!ConvertNode(render_frame_info->global_frame_token,
                        *frame_page_content.root_node, page_content_map,
                        frame_token_set, get_render_frame_info, metadata,
-
                        proto_child_frame_node)) {
         return false;
       }
@@ -971,5 +974,6 @@
 
 RenderFrameInfo::RenderFrameInfo() = default;
 RenderFrameInfo::RenderFrameInfo(const RenderFrameInfo& other) = default;
+RenderFrameInfo::~RenderFrameInfo() = default;
 
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/content/browser/page_content_proto_util.h b/components/optimization_guide/content/browser/page_content_proto_util.h
index 3f0a0ea..375ddfd 100644
--- a/components/optimization_guide/content/browser/page_content_proto_util.h
+++ b/components/optimization_guide/content/browser/page_content_proto_util.h
@@ -22,12 +22,13 @@
  public:
   RenderFrameInfo();
   RenderFrameInfo(const RenderFrameInfo& other);
-  ~RenderFrameInfo() = default;
+  ~RenderFrameInfo();
 
   content::GlobalRenderFrameHostToken global_frame_token;
   url::Origin source_origin;
   GURL url;
   std::string serialized_server_token;
+  std::optional<optimization_guide::proto::MediaData> media_data;
 };
 
 struct TargetNodeInfo {
diff --git a/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc b/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc
index 09e4647..0c522f3 100644
--- a/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc
+++ b/components/optimization_guide/content/browser/page_content_proto_util_unittest.cc
@@ -47,6 +47,14 @@
   return page_content;
 }
 
+optimization_guide::proto::MediaData CreateMediaData() {
+  optimization_guide::proto::MediaData media_data;
+  media_data.set_media_data_type(
+      optimization_guide::proto::MediaDataType::MEDIA_DATA_TYPE_AUDIO);
+  media_data.set_duration_milliseconds(10000);
+  return media_data;
+}
+
 blink::mojom::AIPageContentNodePtr CreateTextNode(
     std::string text,
     blink::mojom::AIPageContentTextSize text_size,
@@ -90,6 +98,7 @@
           render_frame_info.url = GURL("https://example.com");
           render_frame_info.serialized_server_token =
               main_frame_token.frame_token.ToString();
+          render_frame_info.media_data = CreateMediaData();
           return render_frame_info;
         }
         return std::nullopt;
@@ -436,6 +445,14 @@
   EXPECT_EQ("Page Title", page_content.proto.main_frame_data().title());
 }
 
+TEST(PageContentProtoUtilTest, MediaDataSet) {
+  auto root_content = CreatePageContent();
+
+  AIPageContentResult page_content;
+  EXPECT_TRUE(ConvertAIPageContentToProto(root_content, page_content));
+  EXPECT_TRUE(page_content.proto.main_frame_data().has_media_data());
+}
+
 TEST(PageContentProtoUtilTest, ConvertTableData) {
   auto root_content = CreatePageContent();
   auto table_node =
@@ -582,6 +599,7 @@
           render_frame_info.global_frame_token = main_frame_token;
         } else {
           render_frame_info.global_frame_token = iframe_token;
+          render_frame_info.media_data = CreateMediaData();
         }
         render_frame_info.source_origin =
             url::Origin::Create(GURL("https://example.com"));
@@ -620,6 +638,9 @@
   EXPECT_EQ(selection.end_node_id(), 2);
   EXPECT_EQ(selection.start_offset(), 3);
   EXPECT_EQ(selection.end_offset(), 4);
+
+  EXPECT_FALSE(page_content.proto.main_frame_data().has_media_data());
+  EXPECT_TRUE(proto_iframe_data.frame_data().has_media_data());
 }
 
 TEST(PageContentProtoUtilTest, AttributeTypeDoesNotMatchData_Form) {
diff --git a/components/optimization_guide/core/delivery/model_util.cc b/components/optimization_guide/core/delivery/model_util.cc
index c42455f5..2f58552 100644
--- a/components/optimization_guide/core/delivery/model_util.cc
+++ b/components/optimization_guide/core/delivery/model_util.cc
@@ -157,6 +157,10 @@
       return "SegmentationIosDefaultBrowserPromo";
     case proto::OPTIMIZATION_TARGET_EDU_CLASSIFIER:
       return "EduClassifier";
+    case proto::OPTIMIZATION_TARGET_PERMISSIONS_AIV4_GEOLOCATION_DESKTOP:
+      return "PermissionsAiv4GeolocationDesktop";
+    case proto::OPTIMIZATION_TARGET_PERMISSIONS_AIV4_NOTIFICATIONS_DESKTOP:
+      return "PermissionsAiv4NotificationsDesktop";
       // Whenever a new value is added, make sure to add it to the OptTarget
       // variant list in
       // //tools/metrics/histograms/metadata/optimization/histograms.xml.
diff --git a/components/optimization_guide/core/model_execution/model_execution_manager.cc b/components/optimization_guide/core/model_execution/model_execution_manager.cc
index 3042999..1c851b7 100644
--- a/components/optimization_guide/core/model_execution/model_execution_manager.cc
+++ b/components/optimization_guide/core/model_execution/model_execution_manager.cc
@@ -386,19 +386,19 @@
   return on_device_model_service_controller_->CanCreateSession(feature);
 }
 
-std::optional<optimization_guide::OnDeviceModelAdaptationMetadata>
+std::optional<OnDeviceModelAdaptationMetadata>
 ModelExecutionManager::GetOnDeviceModelAdaptationMetadata(
-    optimization_guide::ModelBasedCapabilityKey feature) {
+    ModelBasedCapabilityKey feature) {
   if (!on_device_model_service_controller_) {
     return std::nullopt;
   }
 
-  optimization_guide::OnDeviceModelAdaptationMetadata* metadata =
+  MaybeAdaptationMetadata metadata =
       on_device_model_service_controller_->GetFeatureMetadata(feature);
-  if (!metadata) {
+  if (!metadata.has_value()) {
     return std::nullopt;
   }
-  return *metadata;
+  return metadata.value();
 }
 
 std::optional<optimization_guide::SamplingParamsConfig>
diff --git a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.cc b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.cc
index cfeef75b..89ccdc7c 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.cc
@@ -4,6 +4,7 @@
 
 #include "components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/metrics/histogram_functions.h"
@@ -40,7 +41,7 @@
       availability);
 }
 
-base::expected<std::unique_ptr<OnDeviceModelAdaptationMetadata>,
+base::expected<OnDeviceModelAdaptationMetadata,
                OnDeviceModelAdaptationAvailability>
 CreateAdaptatonMetadataFromModelExecutionConfig(
     ModelBasedCapabilityKey feature,
@@ -60,37 +61,62 @@
     return base::unexpected(OnDeviceModelAdaptationAvailability::
                                 kAdaptationModelExecutionConfigInvalid);
   }
-  return base::ok(OnDeviceModelAdaptationMetadata::New(
+  return OnDeviceModelAdaptationMetadata(
       asset_paths.get(), version,
-      base::MakeRefCounted<OnDeviceModelFeatureAdapter>(std::move(config))));
+      base::MakeRefCounted<OnDeviceModelFeatureAdapter>(std::move(config)));
 }
 
-std::unique_ptr<OnDeviceModelAdaptationMetadata>
-OnDeviceModelAdaptationMetadataCreated(
+MaybeAdaptationMetadata OnDeviceModelAdaptationMetadataCreated(
     ModelBasedCapabilityKey feature,
-    base::expected<std::unique_ptr<OnDeviceModelAdaptationMetadata>,
+    base::expected<OnDeviceModelAdaptationMetadata,
                    OnDeviceModelAdaptationAvailability> metadata) {
   if (!metadata.has_value()) {
     RecordAdaptationModelAvailability(feature, metadata.error());
-    return nullptr;
+    return base::unexpected(AdaptationUnavailability::kNotSupported);
   }
   RecordAdaptationModelAvailability(
       feature, OnDeviceModelAdaptationAvailability::kAvailable);
   return std::move(metadata.value());
 }
 
-}  // namespace
-
-// static
-std::unique_ptr<OnDeviceModelAdaptationMetadata>
-OnDeviceModelAdaptationMetadata::New(
-    on_device_model::AdaptationAssetPaths* asset_paths,
-    int64_t version,
-    scoped_refptr<OnDeviceModelFeatureAdapter> adapter) {
-  return base::WrapUnique(new OnDeviceModelAdaptationMetadata(
-      asset_paths, version, std::move(adapter)));
+std::optional<OnDeviceModelAdaptationAvailability>
+DetectBaseModelIncompatibility(const optimization_guide::ModelInfo& model_info,
+                               const OnDeviceBaseModelSpec registered_spec) {
+  const std::optional<proto::Any>& metadata = model_info.GetModelMetadata();
+  if (!metadata.has_value()) {
+    return OnDeviceModelAdaptationAvailability::kAdaptationModelInvalid;
+  }
+  auto supported_model_spec =
+      ParsedAnyMetadata<proto::OnDeviceBaseModelMetadata>(metadata.value());
+  if (!supported_model_spec) {
+    return OnDeviceModelAdaptationAvailability::kAdaptationModelInvalid;
+  }
+  // Check for incompatibility when base model override is not specified
+  if (!switches::GetOnDeviceModelExecutionOverride()) {
+    if (supported_model_spec->base_model_name() != registered_spec.model_name ||
+        supported_model_spec->base_model_version() !=
+            registered_spec.model_version) {
+      return OnDeviceModelAdaptationAvailability::kAdaptationModelIncompatible;
+    }
+  }
+  return std::nullopt;
 }
 
+std::unique_ptr<on_device_model::AdaptationAssetPaths> MaybeGetAdaptationPaths(
+    const optimization_guide::ModelInfo& model_info) {
+  auto weights_file = model_info.GetAdditionalFileWithBaseName(
+      kOnDeviceModelAdaptationWeightsFile);
+  if (!weights_file) {
+    return nullptr;
+  }
+  auto adaptation_assets =
+      std::make_unique<on_device_model::AdaptationAssetPaths>();
+  adaptation_assets->weights = *weights_file;
+  return adaptation_assets;
+}
+
+}  // namespace
+
 OnDeviceModelAdaptationMetadata::OnDeviceModelAdaptationMetadata(
     on_device_model::AdaptationAssetPaths* asset_paths,
     int64_t version,
@@ -101,8 +127,13 @@
 
 OnDeviceModelAdaptationMetadata::OnDeviceModelAdaptationMetadata(
     const OnDeviceModelAdaptationMetadata&) = default;
+OnDeviceModelAdaptationMetadata::OnDeviceModelAdaptationMetadata(
+    OnDeviceModelAdaptationMetadata&&) = default;
 OnDeviceModelAdaptationMetadata::~OnDeviceModelAdaptationMetadata() = default;
 
+OnDeviceModelAdaptationMetadata& OnDeviceModelAdaptationMetadata::operator=(
+    OnDeviceModelAdaptationMetadata&&) = default;
+
 bool OnDeviceModelAdaptationMetadata::operator==(
     const OnDeviceModelAdaptationMetadata& other) const {
   return version_ == other.version_ && asset_paths_ == other.asset_paths_;
@@ -161,29 +192,31 @@
     const OnDeviceModelComponentState* state,
     bool was_feature_recently_used) {
   CHECK(model_provider_);
-  if (!state) {
-    Unregister();
-    on_load_fn_.Run(nullptr);
+
+  std::optional<OnDeviceBaseModelSpec> new_spec =
+      state ? std::make_optional(state->GetBaseModelSpec()) : std::nullopt;
+  if (new_spec && *new_spec == registered_spec_) {
+    return;
+  }
+
+  // The spec has changed, so we need to unregister the old observer.
+  Unregister();
+  on_load_fn_.Run(base::unexpected(AdaptationUnavailability::kUpdatePending));
+
+  if (!new_spec) {
     RecordAdaptationModelAvailability(
         feature_, OnDeviceModelAdaptationAvailability::kBaseModelUnavailable);
     return;
   }
-  auto spec = state->GetBaseModelSpec();
-  if (registered_spec_ == spec) {
+
+  if (!switches::GetOnDeviceModelExecutionOverride() &&
+      !was_feature_recently_used) {
+    RecordAdaptationModelAvailability(
+        feature_, OnDeviceModelAdaptationAvailability::kFeatureNotRecentlyUsed);
     return;
   }
-  Unregister();
-  on_load_fn_.Run(nullptr);
-  if (!switches::GetOnDeviceModelExecutionOverride()) {
-    if (!was_feature_recently_used) {
-      RecordAdaptationModelAvailability(
-          feature_,
-          OnDeviceModelAdaptationAvailability::kFeatureNotRecentlyUsed);
-      return;
-    }
-  }
 
-  registered_spec_ = state->GetBaseModelSpec();
+  registered_spec_ = *new_spec;
   proto::Any any_metadata;
   any_metadata.set_type_url(
       "type.googleapis.com/"
@@ -219,10 +252,22 @@
     proto::OptimizationTarget optimization_target,
     base::optional_ref<const ModelInfo> model_info) {
   CHECK_EQ(optimization_target, target_);
-  on_load_fn_.Run(nullptr);
-  auto result = ProcessModelUpdate(model_info);
-  if (!result.has_value()) {
-    RecordAdaptationModelAvailability(feature_, result.error());
+  CHECK(registered_spec_.has_value());
+  if (!model_info.has_value()) {
+    // The server has indicated no adaptation is available.
+    RecordAdaptationModelAvailability(
+        feature_,
+        OnDeviceModelAdaptationAvailability::kAdaptationModelUnavailable);
+    on_load_fn_.Run(base::unexpected(AdaptationUnavailability::kNotSupported));
+    return;
+  }
+  // The current adaptation's files might get cleaned up, so stop using it.
+  on_load_fn_.Run(base::unexpected(AdaptationUnavailability::kUpdatePending));
+  auto error = DetectBaseModelIncompatibility(*model_info, *registered_spec_);
+  if (error) {
+    RecordAdaptationModelAvailability(feature_, *error);
+    // Likely a stale asset that was on disk, and we haven't fetched yet.
+    // Don't notify the controller yet.
     return;
   }
   auto execution_config_file = model_info->GetAdditionalFileWithBaseName(
@@ -231,7 +276,7 @@
     RecordAdaptationModelAvailability(
         feature_, OnDeviceModelAdaptationAvailability::
                       kAdaptationModelExecutionConfigInvalid);
-
+    on_load_fn_.Run(base::unexpected(AdaptationUnavailability::kNotSupported));
     return;
   }
 
@@ -239,56 +284,11 @@
       FROM_HERE,
       base::BindOnce(&ReadOnDeviceModelExecutionConfig, *execution_config_file),
       base::BindOnce(&CreateAdaptatonMetadataFromModelExecutionConfig, feature_,
-                     std::move(result.value()), model_info->GetVersion())
+                     MaybeGetAdaptationPaths(*model_info),
+                     model_info->GetVersion())
           .Then(
               base::BindOnce(&OnDeviceModelAdaptationMetadataCreated, feature_))
           .Then(on_load_fn_));
 }
 
-base::expected<std::unique_ptr<on_device_model::AdaptationAssetPaths>,
-               OnDeviceModelAdaptationAvailability>
-OnDeviceModelAdaptationLoader::ProcessModelUpdate(
-    base::optional_ref<const optimization_guide::ModelInfo> model_info) {
-  if (!model_info.has_value()) {
-    return base::unexpected(
-        OnDeviceModelAdaptationAvailability::kAdaptationModelUnavailable);
-  }
-  const std::optional<proto::Any>& metadata = model_info->GetModelMetadata();
-  if (!metadata.has_value()) {
-    return base::unexpected(
-        OnDeviceModelAdaptationAvailability::kAdaptationModelInvalid);
-  }
-  auto supported_model_spec =
-      ParsedAnyMetadata<proto::OnDeviceBaseModelMetadata>(metadata.value());
-  if (!supported_model_spec) {
-    return base::unexpected(
-        OnDeviceModelAdaptationAvailability::kAdaptationModelInvalid);
-  }
-  // Check for incompatibility when base model override is not specified
-  if (!switches::GetOnDeviceModelExecutionOverride()) {
-    if (!registered_spec_) {
-      return base::unexpected(
-          OnDeviceModelAdaptationAvailability::kBaseModelUnavailable);
-    }
-    if (supported_model_spec->base_model_name() !=
-            registered_spec_->model_name ||
-        supported_model_spec->base_model_version() !=
-            registered_spec_->model_version) {
-      return base::unexpected(
-          OnDeviceModelAdaptationAvailability::kAdaptationModelIncompatible);
-    }
-  }
-
-  auto weights_file = model_info->GetAdditionalFileWithBaseName(
-      kOnDeviceModelAdaptationWeightsFile);
-  if (!weights_file) {
-    // Return that the weights file was not provided.
-    return base::ok(nullptr);
-  }
-  auto adaptations_assets =
-      std::make_unique<on_device_model::AdaptationAssetPaths>();
-  adaptations_assets->weights = *weights_file;
-  return base::ok(std::move(adaptations_assets));
-}
-
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h
index 67b21f2..1ec6c03 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h
+++ b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h
@@ -25,18 +25,59 @@
 class OnDeviceModelFeatureAdapter;
 class OnDeviceModelMetadata;
 class OptimizationGuideModelProvider;
-enum class OnDeviceModelAdaptationAvailability;
+
+// Detailed availability reason for histograms recording.
+enum class OnDeviceModelAdaptationAvailability {
+  // Adaptation model was available.
+  kAvailable = 0,
+
+  // Base model was not available.
+  kBaseModelUnavailable = 1,
+
+  // Base model spec was invalid, so adaptation model cannot be fetched.
+  kBaseModelSpecInvalid = 2,
+
+  // Adaptation model was not available.
+  kAdaptationModelUnavailable = 3,
+
+  // The received adaptation model was invalid.
+  kAdaptationModelInvalid = 4,
+
+  // The received adaptation model was incompatible with the base model.
+  kAdaptationModelIncompatible = 5,
+
+  // The execution config in the adaptation model was invalid.
+  kAdaptationModelExecutionConfigInvalid = 6,
+
+  // The model execution feature was not recently used.
+  kFeatureNotRecentlyUsed = 7,
+
+  // This must be kept in sync with OnDeviceModelAdaptationAvailability in
+  // optimization/enums.xml.
+  kMaxValue = kFeatureNotRecentlyUsed,
+};
+
+// Indication of why a feature adaptation is not available.
+// Simplification of OnDeviceModelAdaptationAvailability which is for
+// metrics purposes.
+enum class AdaptationUnavailability {
+  // The adaptation is being replaced.
+  kUpdatePending = 0,
+  // No model is expected to be available.
+  kNotSupported = 1,
+};
 
 class OnDeviceModelAdaptationMetadata {
  public:
-  static std::unique_ptr<OnDeviceModelAdaptationMetadata> New(
+  OnDeviceModelAdaptationMetadata(
       on_device_model::AdaptationAssetPaths* asset_paths,
       int64_t version,
       scoped_refptr<OnDeviceModelFeatureAdapter> adapter);
-
   OnDeviceModelAdaptationMetadata(const OnDeviceModelAdaptationMetadata&);
+  OnDeviceModelAdaptationMetadata(OnDeviceModelAdaptationMetadata&&);
   ~OnDeviceModelAdaptationMetadata();
 
+  OnDeviceModelAdaptationMetadata& operator=(OnDeviceModelAdaptationMetadata&&);
   bool operator==(const OnDeviceModelAdaptationMetadata& other) const;
 
   const on_device_model::AdaptationAssetPaths* asset_paths() const;
@@ -48,17 +89,14 @@
   int64_t version() const { return version_; }
 
  private:
-  friend class OnDeviceModelServiceControllerTest;
-
-  OnDeviceModelAdaptationMetadata(
-      on_device_model::AdaptationAssetPaths* asset_paths,
-      int64_t version,
-      scoped_refptr<OnDeviceModelFeatureAdapter> adapter);
   std::optional<on_device_model::AdaptationAssetPaths> asset_paths_;
   int64_t version_;
   scoped_refptr<OnDeviceModelFeatureAdapter> adapter_;
 };
 
+using MaybeAdaptationMetadata =
+    base::expected<OnDeviceModelAdaptationMetadata, AdaptationUnavailability>;
+
 // Loads model adaptation assets for a particular feature. Performs adaptation
 // model compatibility checks with the base model and reloads the assets if the
 // base model changes.
@@ -67,7 +105,8 @@
       public OnDeviceModelComponentStateManager::Observer {
  public:
   using OnLoadFn = base::RepeatingCallback<void(
-      std::unique_ptr<OnDeviceModelAdaptationMetadata>)>;
+      base::expected<OnDeviceModelAdaptationMetadata,
+                     AdaptationUnavailability>)>;
 
   OnDeviceModelAdaptationLoader(
       ModelBasedCapabilityKey feature,
@@ -101,11 +140,6 @@
   void MaybeRegisterModelDownload(const OnDeviceModelComponentState* state,
                                   bool was_feature_recently_used);
 
-  base::expected<std::unique_ptr<on_device_model::AdaptationAssetPaths>,
-                 OnDeviceModelAdaptationAvailability>
-  ProcessModelUpdate(
-      base::optional_ref<const optimization_guide::ModelInfo> model_info);
-
   ModelBasedCapabilityKey feature_;
   proto::OptimizationTarget target_;
 
diff --git a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc
index 6d42d64..543fa04 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_adaptation_loader_unittest.cc
@@ -9,6 +9,8 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/types/expected.h"
 #include "components/optimization_guide/core/delivery/test_model_info_builder.h"
 #include "components/optimization_guide/core/delivery/test_optimization_guide_model_provider.h"
 #include "components/optimization_guide/core/model_execution/feature_keys.h"
@@ -17,12 +19,16 @@
 #include "components/optimization_guide/core/model_execution/on_device_model_feature_adapter.h"
 #include "components/optimization_guide/core/model_execution/performance_class.h"
 #include "components/optimization_guide/core/model_execution/test/fake_model_assets.h"
+#include "components/optimization_guide/core/model_execution/test/fake_model_broker.h"
+#include "components/optimization_guide/core/model_execution/test/fake_remote.h"
+#include "components/optimization_guide/core/model_execution/test/feature_config_builder.h"
 #include "components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h"
 #include "components/optimization_guide/core/optimization_guide_constants.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/proto/on_device_base_model_metadata.pb.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
 
 namespace optimization_guide {
 
@@ -58,6 +64,32 @@
   ASSERT_TRUE(base::WriteFile(file_path, serialized_config));
 }
 
+class FakeModelProvider : public TestOptimizationGuideModelProvider {
+ public:
+  void AddObserverForOptimizationTargetModel(
+      proto::OptimizationTarget optimization_target,
+      const std::optional<optimization_guide::proto::Any>& model_metadata,
+      OptimizationTargetModelObserver* observer) override {
+    observers_[optimization_target] = observer;
+  }
+
+  OptimizationTargetModelObserver* GetObserver(
+      proto::OptimizationTarget optimization_target) {
+    return observers_[optimization_target];
+  }
+  std::optional<proto::Any> GetMetadata(
+      proto::OptimizationTarget optimization_target) {
+    return metadata_[optimization_target];
+  }
+
+ private:
+  absl::flat_hash_map<proto::OptimizationTarget,
+                      OptimizationTargetModelObserver*>
+      observers_;
+  absl::flat_hash_map<proto::OptimizationTarget, std::optional<proto::Any>>
+      metadata_;
+};
+
 }  // namespace
 
 class FakeOptimizationGuideModelProvider
@@ -131,8 +163,7 @@
   base::FilePath temp_dir() const { return temp_dir_.GetPath(); }
 
  protected:
-  void OnModelAdaptationLoaded(
-      std::unique_ptr<OnDeviceModelAdaptationMetadata> adaptation_metadata) {
+  void OnModelAdaptationLoaded(MaybeAdaptationMetadata adaptation_metadata) {
     adaptation_metadata_ = std::move(adaptation_metadata);
   }
 
@@ -145,7 +176,8 @@
       &local_state_};
   FakeOptimizationGuideModelProvider model_provider_;
   std::unique_ptr<OnDeviceModelAdaptationLoader> adaptation_loader_;
-  std::unique_ptr<OnDeviceModelAdaptationMetadata> adaptation_metadata_;
+  MaybeAdaptationMetadata adaptation_metadata_{
+      base::unexpected(AdaptationUnavailability::kUpdatePending)};
   base::HistogramTester histogram_tester_;
 };
 
@@ -155,7 +187,7 @@
       "OptimizationGuide.ModelExecution.OnDeviceAdaptationModelAvailability."
       "Test",
       OnDeviceModelAdaptationAvailability::kBaseModelUnavailable, 1);
-  EXPECT_FALSE(adaptation_metadata_);
+  EXPECT_FALSE(adaptation_metadata_.has_value());
 }
 
 TEST_F(OnDeviceModelAdaptationLoaderTest, AdaptationModelInvalid) {
@@ -170,7 +202,7 @@
       "OptimizationGuide.ModelExecution.OnDeviceAdaptationModelAvailability."
       "Test",
       OnDeviceModelAdaptationAvailability::kAdaptationModelInvalid, 1);
-  EXPECT_FALSE(adaptation_metadata_);
+  EXPECT_FALSE(adaptation_metadata_.has_value());
 }
 
 TEST_F(OnDeviceModelAdaptationLoaderTest, AdaptationModelIncompatible) {
@@ -191,7 +223,7 @@
       "OptimizationGuide.ModelExecution.OnDeviceAdaptationModelAvailability."
       "Test",
       OnDeviceModelAdaptationAvailability::kAdaptationModelIncompatible, 1);
-  EXPECT_FALSE(adaptation_metadata_);
+  EXPECT_FALSE(adaptation_metadata_.has_value());
 }
 
 TEST_F(OnDeviceModelAdaptationLoaderTest,
@@ -217,7 +249,7 @@
       OnDeviceModelAdaptationAvailability::
           kAdaptationModelExecutionConfigInvalid,
       1);
-  EXPECT_FALSE(adaptation_metadata_);
+  EXPECT_FALSE(adaptation_metadata_.has_value());
 }
 
 TEST_F(OnDeviceModelAdaptationLoaderTest,
@@ -245,7 +277,7 @@
       OnDeviceModelAdaptationAvailability::
           kAdaptationModelExecutionConfigInvalid,
       1);
-  EXPECT_FALSE(adaptation_metadata_);
+  EXPECT_FALSE(adaptation_metadata_.has_value());
 }
 
 TEST_F(OnDeviceModelAdaptationLoaderTest,
@@ -277,7 +309,7 @@
       OnDeviceModelAdaptationAvailability::
           kAdaptationModelExecutionConfigInvalid,
       1);
-  EXPECT_FALSE(adaptation_metadata_);
+  EXPECT_FALSE(adaptation_metadata_.has_value());
 }
 
 TEST_F(OnDeviceModelAdaptationLoaderTest, AdaptationModelValid) {
@@ -306,7 +338,7 @@
       "OptimizationGuide.ModelExecution.OnDeviceAdaptationModelAvailability."
       "Test",
       OnDeviceModelAdaptationAvailability::kAvailable, 1);
-  EXPECT_TRUE(adaptation_metadata_);
+  EXPECT_TRUE(adaptation_metadata_.has_value());
   EXPECT_EQ(base::FilePath(kOnDeviceModelAdaptationWeightsFile),
             adaptation_metadata_->asset_paths()->weights.BaseName());
 }
@@ -336,7 +368,7 @@
       "OptimizationGuide.ModelExecution.OnDeviceAdaptationModelAvailability."
       "Test",
       OnDeviceModelAdaptationAvailability::kAvailable, 1);
-  EXPECT_TRUE(adaptation_metadata_);
+  EXPECT_TRUE(adaptation_metadata_.has_value());
   EXPECT_FALSE(adaptation_metadata_->asset_paths());
 }
 
@@ -380,9 +412,52 @@
       "OptimizationGuide.ModelExecution.OnDeviceAdaptationModelAvailability."
       "Test",
       OnDeviceModelAdaptationAvailability::kAvailable, 1);
-  EXPECT_TRUE(adaptation_metadata_);
+  EXPECT_TRUE(adaptation_metadata_.has_value());
   EXPECT_EQ(base::FilePath(kOnDeviceModelAdaptationWeightsFile),
             adaptation_metadata_->asset_paths()->weights.BaseName());
 }
 
+TEST(OnDeviceModelAdaptationLoaderTest2, UnavailableAdaptationRejectsSession) {
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  FakeAdaptationAsset compose_asset{{
+      .config = SimpleComposeConfig(),
+  }};
+  FakeModelBroker broker{compose_asset};
+  OptimizationGuideLogger logger;
+
+  // Mark feature used to trigger download.
+  model_execution::prefs::RecordFeatureUsage(&broker.local_state(),
+                                             ModelBasedCapabilityKey::kTest);
+
+  mojo::PendingReceiver<mojom::ModelBroker> pending_broker;
+  ModelBrokerClient broker_client(
+      broker.BindAndPassRemote(),
+      CreateSessionArgs(logger.GetWeakPtr(), FailOnRemoteFallback()));
+
+  base::test::TestFuture<
+      std::unique_ptr<OptimizationGuideModelExecutor::Session>>
+      session_future;
+  broker_client.CreateSession(mojom::ModelBasedCapabilityKey::kTest,
+                              std::nullopt, session_future.GetCallback());
+
+  // Session should not resolve yet, because test adaptation asset has a
+  // kUpdatePending status.
+  task_environment_.FastForwardBy(base::Hours(1));
+  ASSERT_FALSE(session_future.IsReady());
+
+  // Emulate receiving info that a adaptation is not available from server.
+  auto target = *features::internal::GetOptimizationTargetForCapability(
+      ModelBasedCapabilityKey::kTest);
+  FakeModelProvider fake_provider;
+  auto asset_manager = broker.CreateAssetManager(&fake_provider);
+  auto* observer = fake_provider.GetObserver(target);
+  ASSERT_TRUE(observer);
+  observer->OnModelUpdated(target, std::nullopt);
+
+  // Session should resolve to unavailable.
+  auto session = session_future.Take();
+  ASSERT_FALSE(session);
+}
+
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/on_device_model_component.cc b/components/optimization_guide/core/model_execution/on_device_model_component.cc
index a69fab5..f7189298 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_component.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_component.cc
@@ -108,8 +108,7 @@
 OnDeviceBaseModelSpec::OnDeviceBaseModelSpec(
     const std::string& model_name,
     const std::string& model_version,
-    const base::flat_set<proto::OnDeviceModelPerformanceHint>&
-        supported_performance_hints)
+    PerformanceHints supported_performance_hints)
     : model_name(model_name),
       model_version(model_version),
       supported_performance_hints(supported_performance_hints) {}
@@ -456,9 +455,9 @@
   return OnDeviceBaseModelSpec(
       *name, *version,
       supported_performance_hint_enum
-          ? base::flat_set<proto::OnDeviceModelPerformanceHint>(
+          ? OnDeviceBaseModelSpec::PerformanceHints(
                 {*supported_performance_hint_enum})
-          : base::flat_set<proto::OnDeviceModelPerformanceHint>({}));
+          : OnDeviceBaseModelSpec::PerformanceHints  ({}));
 }
 
 std::optional<proto::OnDeviceModelPerformanceHint>
diff --git a/components/optimization_guide/core/model_execution/on_device_model_component.h b/components/optimization_guide/core/model_execution/on_device_model_component.h
index 43f7b48..3ad6c69 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_component.h
+++ b/components/optimization_guide/core/model_execution/on_device_model_component.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "base/containers/flat_set.h"
+#include "base/containers/enum_set.h"
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
@@ -77,12 +77,16 @@
 // Wraps the specification needed to determine compatibility of the
 // on-device base model with any feature specific code.
 struct OnDeviceBaseModelSpec {
+  using PerformanceHints =
+      base::EnumSet<proto::OnDeviceModelPerformanceHint,
+                    proto::OnDeviceModelPerformanceHint_MIN,
+                    proto::OnDeviceModelPerformanceHint_MAX>;
+
   OnDeviceBaseModelSpec();
   OnDeviceBaseModelSpec(
       const std::string& model_name,
       const std::string& model_version,
-      const base::flat_set<proto::OnDeviceModelPerformanceHint>&
-          supported_performance_hints);
+      PerformanceHints supported_performance_hints);
   ~OnDeviceBaseModelSpec();
   OnDeviceBaseModelSpec(const OnDeviceBaseModelSpec&);
 
@@ -93,8 +97,7 @@
   // The version of the base model currently available on-device.
   std::string model_version;
   // The supported performance hints for this device and base model.
-  base::flat_set<proto::OnDeviceModelPerformanceHint>
-      supported_performance_hints;
+  PerformanceHints supported_performance_hints;
 };
 
 // Manages the state of the on-device component.
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
index 0f88754..9a6586a2 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
@@ -194,8 +194,8 @@
 
   CHECK(base_model_controller_->model_metadata());
   CHECK(features::internal::GetOptimizationTargetForCapability(feature));
-  auto* adaptation_metadata = GetFeatureMetadata(feature);
-  CHECK(adaptation_metadata);
+  MaybeAdaptationMetadata adaptation_metadata = GetFeatureMetadata(feature);
+  CHECK(adaptation_metadata.has_value());
 
   OnDeviceOptions opts;
   opts.model_client = std::make_unique<OnDeviceModelClient>(
@@ -247,21 +247,15 @@
 
 void OnDeviceModelServiceController::MaybeUpdateModelAdaptation(
     ModelBasedCapabilityKey feature,
-    std::unique_ptr<OnDeviceModelAdaptationMetadata> adaptation_metadata) {
-  if (!adaptation_metadata) {
-    model_adaptation_metadata_.erase(feature);
-    base_model_controller_->EraseController(feature);
-    UpdateSolutionProvider(feature);
-    return;
-  }
-  auto it = model_adaptation_metadata_.find(feature);
-  if (it != model_adaptation_metadata_.end() &&
-      it->second == *adaptation_metadata) {
+    base::expected<OnDeviceModelAdaptationMetadata, AdaptationUnavailability>
+        adaptation_metadata) {
+  MaybeAdaptationMetadata& current_metadata = GetFeatureMetadata(feature);
+  if (current_metadata == adaptation_metadata) {
     // Duplicate update (can be caused by multiple profiles).
     // Don't invalidate the existing controller.
     return;
   }
-  model_adaptation_metadata_.emplace(feature, *adaptation_metadata);
+  current_metadata = std::move(adaptation_metadata);
   base_model_controller_->EraseController(feature);
   UpdateSolutionProvider(feature);
 }
@@ -318,14 +312,14 @@
   }
 }
 
-OnDeviceModelAdaptationMetadata*
-OnDeviceModelServiceController::GetFeatureMetadata(
+MaybeAdaptationMetadata& OnDeviceModelServiceController::GetFeatureMetadata(
     ModelBasedCapabilityKey feature) {
-  if (auto it = model_adaptation_metadata_.find(feature);
-      it != model_adaptation_metadata_.end()) {
-    return &it->second;
-  }
-  return nullptr;
+  auto it =
+      model_adaptation_metadata_
+          .emplace(feature,
+                   base::unexpected(AdaptationUnavailability::kUpdatePending))
+          .first;
+  return it->second;
 }
 
 void OnDeviceModelServiceController::AddOnDeviceModelAvailabilityChangeObserver(
@@ -364,8 +358,12 @@
   }
 
   // Check feature config.
-  auto* metadata = GetFeatureMetadata(feature);
-  if (!metadata) {
+  MaybeAdaptationMetadata metadata = GetFeatureMetadata(feature);
+  if (!metadata.has_value()) {
+    if (metadata.error() == AdaptationUnavailability::kNotSupported) {
+      return base::unexpected(
+          OnDeviceModelEligibilityReason::kModelAdaptationNotAvailable);
+    }
     return base::unexpected(
         OnDeviceModelEligibilityReason::kConfigNotAvailableForFeature);
   }
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
index ebf400d..024cab8 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
+++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.h
@@ -26,6 +26,7 @@
 #include "base/types/pass_key.h"
 #include "components/optimization_guide/core/delivery/model_info.h"
 #include "components/optimization_guide/core/model_execution/feature_keys.h"
+#include "components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_component.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_metadata.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_validator.h"
@@ -111,9 +112,8 @@
   void UpdateModel(std::unique_ptr<OnDeviceModelMetadata> model_metadata);
 
   // Updates the model adaptation for the feature.
-  void MaybeUpdateModelAdaptation(
-      ModelBasedCapabilityKey feature,
-      std::unique_ptr<OnDeviceModelAdaptationMetadata> adaptation_metadata);
+  void MaybeUpdateModelAdaptation(ModelBasedCapabilityKey feature,
+                                  MaybeAdaptationMetadata adaptation_metadata);
 
   // Add/remove observers for notifying on-device model availability changes.
   void AddOnDeviceModelAvailabilityChangeObserver(
@@ -130,14 +130,8 @@
     return weak_ptr_factory_.GetWeakPtr();
   }
 
-  OnDeviceModelAdaptationMetadata* GetFeatureMetadata(
-      ModelBasedCapabilityKey feature);
-
-  const base::flat_map<ModelBasedCapabilityKey,
-                       OnDeviceModelAdaptationMetadata>&
-  model_adaptation_metadata() const {
-    return model_adaptation_metadata_;
-  }
+  // Retrieves the object storing the adaptation metadata for 'feature'.
+  MaybeAdaptationMetadata& GetFeatureMetadata(ModelBasedCapabilityKey feature);
 
   void BindBroker(mojo::PendingReceiver<mojom::ModelBroker> receiver) {
     receivers_.Add(this, std::move(receiver));
@@ -378,7 +372,7 @@
   // Map from feature to its adaptation assets. Present only for features that
   // have valid model adaptation. It could be missing for features that require
   // model adaptation, but they have not been loaded yet.
-  base::flat_map<ModelBasedCapabilityKey, OnDeviceModelAdaptationMetadata>
+  base::flat_map<ModelBasedCapabilityKey, MaybeAdaptationMetadata>
       model_adaptation_metadata_;
 
   std::map<ModelBasedCapabilityKey, SolutionProvider> solution_providers_;
diff --git a/components/optimization_guide/core/model_execution/test/fake_model_assets.cc b/components/optimization_guide/core/model_execution/test/fake_model_assets.cc
index f316dcc..6826908 100644
--- a/components/optimization_guide/core/model_execution/test/fake_model_assets.cc
+++ b/components/optimization_guide/core/model_execution/test/fake_model_assets.cc
@@ -74,7 +74,7 @@
     CHECK(base::WriteFile(paths_->weights,
                           base::NumberToString(content.weight.value())));
   }
-  metadata_ = OnDeviceModelAdaptationMetadata::New(
+  metadata_ = std::make_unique<OnDeviceModelAdaptationMetadata>(
       paths_.get(), version(),
       base::MakeRefCounted<OnDeviceModelFeatureAdapter>(
           std::move(content.config)));
diff --git a/components/optimization_guide/core/model_execution/test/fake_model_assets.h b/components/optimization_guide/core/model_execution/test/fake_model_assets.h
index 86e63b8..71f311e 100644
--- a/components/optimization_guide/core/model_execution/test/fake_model_assets.h
+++ b/components/optimization_guide/core/model_execution/test/fake_model_assets.h
@@ -71,9 +71,7 @@
 
   int64_t version() const { return 12345; }
   ModelBasedCapabilityKey feature() const { return feature_; }
-  std::unique_ptr<OnDeviceModelAdaptationMetadata> metadata() const {
-    return std::make_unique<OnDeviceModelAdaptationMetadata>(*metadata_);
-  }
+  OnDeviceModelAdaptationMetadata metadata() const { return *metadata_; }
 
   void SendTo(OnDeviceModelServiceController& controller) const;
 
diff --git a/components/optimization_guide/core/model_execution/test/fake_model_broker.cc b/components/optimization_guide/core/model_execution/test/fake_model_broker.cc
index b4bfdde..d59c6d4 100644
--- a/components/optimization_guide/core/model_execution/test/fake_model_broker.cc
+++ b/components/optimization_guide/core/model_execution/test/fake_model_broker.cc
@@ -6,9 +6,11 @@
 
 #include <memory>
 
+#include "base/types/expected.h"
 #include "components/optimization_guide/core/model_execution/model_execution_features.h"
 #include "components/optimization_guide/core/model_execution/model_execution_prefs.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_access_controller.h"
+#include "components/optimization_guide/core/model_execution/on_device_model_adaptation_loader.h"
 #include "components/optimization_guide/core/model_execution/on_device_model_service_controller.h"
 #include "components/optimization_guide/core/model_execution/performance_class.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
@@ -29,7 +31,8 @@
         {{"on_device_model_validation_delay", "0"}}}},
       {});
   model_execution::prefs::RegisterLocalStatePrefs(local_state_.registry());
-  UpdatePerformanceClassPref(&local_state_, OnDeviceModelPerformanceClass::kHigh);
+  UpdatePerformanceClassPref(&local_state_,
+                             OnDeviceModelPerformanceClass::kHigh);
   auto access_controller =
       std::make_unique<OnDeviceModelAccessController>(local_state_);
   test_controller_ = std::make_unique<OnDeviceModelServiceController>(
@@ -51,9 +54,18 @@
 void FakeModelBroker::UpdateModelAdaptation(const FakeAdaptationAsset& asset) {
   // First clear the current adaptation, then add the new asset to force an
   // update.
-  test_controller_->MaybeUpdateModelAdaptation(asset.feature(), nullptr);
+  test_controller_->MaybeUpdateModelAdaptation(
+      asset.feature(),
+      base::unexpected(AdaptationUnavailability::kUpdatePending));
   test_controller_->MaybeUpdateModelAdaptation(asset.feature(),
                                                asset.metadata());
 }
 
+std::unique_ptr<OnDeviceAssetManager> FakeModelBroker::CreateAssetManager(
+    OptimizationGuideModelProvider* provider) {
+  return std::make_unique<OnDeviceAssetManager>(
+      &local_state_, test_controller_->GetWeakPtr(),
+      component_manager_.get()->GetWeakPtr(), provider);
+}
+
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/model_execution/test/fake_model_broker.h b/components/optimization_guide/core/model_execution/test/fake_model_broker.h
index ac97da8..8ef2ff3f 100644
--- a/components/optimization_guide/core/model_execution/test/fake_model_broker.h
+++ b/components/optimization_guide/core/model_execution/test/fake_model_broker.h
@@ -5,9 +5,13 @@
 #ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_EXECUTION_TEST_FAKE_MODEL_BROKER_H_
 #define COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_EXECUTION_TEST_FAKE_MODEL_BROKER_H_
 
+#include <memory>
+
 #include "base/memory/scoped_refptr.h"
 #include "base/test/scoped_feature_list.h"
+#include "components/optimization_guide/core/delivery/optimization_guide_model_provider.h"
 #include "components/optimization_guide/core/model_execution/model_broker_client.h"
+#include "components/optimization_guide/core/model_execution/on_device_asset_manager.h"
 #include "components/optimization_guide/core/model_execution/test/fake_model_assets.h"
 #include "components/optimization_guide/core/model_execution/test/feature_config_builder.h"
 #include "components/optimization_guide/core/model_execution/test/test_on_device_model_component_state_manager.h"
@@ -35,6 +39,11 @@
     test_controller_->MaybeUpdateSafetyModel(model_info);
   }
 
+  std::unique_ptr<OnDeviceAssetManager> CreateAssetManager(
+      OptimizationGuideModelProvider* provider);
+
+  TestingPrefServiceSimple& local_state() { return local_state_; }
+
  private:
   base::test::ScopedFeatureList feature_list_;
   TestingPrefServiceSimple local_state_;
diff --git a/components/optimization_guide/core/optimization_guide_enums.h b/components/optimization_guide/core/optimization_guide_enums.h
index bcd7724..ec5001e 100644
--- a/components/optimization_guide/core/optimization_guide_enums.h
+++ b/components/optimization_guide/core/optimization_guide_enums.h
@@ -313,36 +313,6 @@
   kMaxValue = kValid,
 };
 
-enum class OnDeviceModelAdaptationAvailability {
-  // Adaptation model was available.
-  kAvailable = 0,
-
-  // Base model was not available.
-  kBaseModelUnavailable = 1,
-
-  // Base model spec was invalid, so adaptation model cannot be fetched.
-  kBaseModelSpecInvalid = 2,
-
-  // Adaptation model was not available.
-  kAdaptationModelUnavailable = 3,
-
-  // The received adaptation model was invalid.
-  kAdaptationModelInvalid = 4,
-
-  // The received adaptation model was incompatible with the base model.
-  kAdaptationModelIncompatible = 5,
-
-  // The execution config in the adaptation model was invalid.
-  kAdaptationModelExecutionConfigInvalid = 6,
-
-  // The model execution feature was not recently used.
-  kFeatureNotRecentlyUsed = 7,
-
-  // This must be kept in sync with OnDeviceModelAdaptationAvailability in
-  // optimization/enums.xml.
-  kMaxValue = kFeatureNotRecentlyUsed,
-};
-
 // Whether a response is complete or not.
 enum class ResponseCompleteness {
   // This is a partial response, more output may follow.
diff --git a/components/optimization_guide/core/optimization_guide_features.cc b/components/optimization_guide/core/optimization_guide_features.cc
index b03af531..7dec045 100644
--- a/components/optimization_guide/core/optimization_guide_features.cc
+++ b/components/optimization_guide/core/optimization_guide_features.cc
@@ -178,6 +178,10 @@
              "AnnotatedPageContentWithActionableElements",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kAnnotatedPageContentWithMediaData,
+             "AnnotatedPageContentWithMediaData",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 const base::FeatureParam<std::string> kPerformanceClassListForOnDeviceModel{
     &kOnDeviceModelPerformanceParams,
     "compatible_on_device_performance_classes", "3,4,5,6"};
diff --git a/components/optimization_guide/core/optimization_guide_features.h b/components/optimization_guide/core/optimization_guide_features.h
index 650fcb3..b48165d 100644
--- a/components/optimization_guide/core/optimization_guide_features.h
+++ b/components/optimization_guide/core/optimization_guide_features.h
@@ -76,6 +76,8 @@
 COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
 BASE_DECLARE_FEATURE(kAnnotatedPageContentWithActionableElements);
 COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
+BASE_DECLARE_FEATURE(kAnnotatedPageContentWithMediaData);
+COMPONENT_EXPORT(OPTIMIZATION_GUIDE_FEATURES)
 BASE_DECLARE_FEATURE(kOptimizationGuideProactivePersonalizedHintsFetching);
 
 // Allows setting feature params for model download configuration, such as
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index add14b2..23d2ce9 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit add14b26475a08db61c03cd8b53835333f184e6a
+Subproject commit 23d2ce9848acc06e84808267b4f7b956f2dfd959
diff --git a/components/optimization_guide/proto/features/summarize.proto b/components/optimization_guide/proto/features/summarize.proto
index 8c05c7f..0af974c 100644
--- a/components/optimization_guide/proto/features/summarize.proto
+++ b/components/optimization_guide/proto/features/summarize.proto
@@ -38,6 +38,7 @@
   SummarizerOutputType output_type = 1;
   SummarizerOutputFormat output_format = 2;
   SummarizerOutputLength output_length = 3;
+  string output_language = 4;  // BCP 47 base language code for responses.
 }
 
 message SummarizeRequest {
diff --git a/components/optimization_guide/proto/models.proto b/components/optimization_guide/proto/models.proto
index 43165dbd..b7b3546 100644
--- a/components/optimization_guide/proto/models.proto
+++ b/components/optimization_guide/proto/models.proto
@@ -256,6 +256,10 @@
   OPTIMIZATION_TARGET_SEGMENTATION_IOS_DEFAULT_BROWSER_PROMO = 63;
   // Target for education classifier.
   OPTIMIZATION_TARGET_EDU_CLASSIFIER = 64;
+  // Target for the text+image AIv4 geolocation permission feature model.
+  OPTIMIZATION_TARGET_PERMISSIONS_AIV4_GEOLOCATION_DESKTOP = 65;
+  // Target for the text+image AIv4 notifications permission feature model.
+  OPTIMIZATION_TARGET_PERMISSIONS_AIV4_NOTIFICATIONS_DESKTOP = 66;
 }
 
 // The model engine versions that can be used to do model inference.
diff --git a/components/os_crypt/sync/keychain_password_mac.h b/components/os_crypt/sync/keychain_password_mac.h
index 0c0b067..b4e14b1 100644
--- a/components/os_crypt/sync/keychain_password_mac.h
+++ b/components/os_crypt/sync/keychain_password_mac.h
@@ -10,8 +10,8 @@
 #include "base/component_export.h"
 #include "base/memory/raw_ref.h"
 
-namespace crypto {
-class AppleKeychain;
+namespace crypto::apple {
+class Keychain;
 }
 
 class COMPONENT_EXPORT(OS_CRYPT) KeychainPassword {
@@ -22,7 +22,7 @@
   using KeychainNameType = const std::string;
 #endif
 
-  KeychainPassword(const crypto::AppleKeychain& keychain);
+  KeychainPassword(const crypto::apple::Keychain& keychain);
 
   KeychainPassword(const KeychainPassword&) = delete;
   KeychainPassword& operator=(const KeychainPassword&) = delete;
@@ -42,7 +42,7 @@
   static COMPONENT_EXPORT(OS_CRYPT) KeychainNameType& GetAccountName();
 
  private:
-  const raw_ref<const crypto::AppleKeychain> keychain_;
+  const raw_ref<const crypto::apple::Keychain> keychain_;
 };
 
 #endif  // COMPONENTS_OS_CRYPT_SYNC_KEYCHAIN_PASSWORD_MAC_H_
diff --git a/components/os_crypt/sync/keychain_password_mac.mm b/components/os_crypt/sync/keychain_password_mac.mm
index 8af3824..1d4c16a 100644
--- a/components/os_crypt/sync/keychain_password_mac.mm
+++ b/components/os_crypt/sync/keychain_password_mac.mm
@@ -15,10 +15,10 @@
 #include "base/rand_util.h"
 #include "base/strings/string_view_util.h"
 #include "build/branding_buildflags.h"
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
 
-using crypto::AppleKeychain;
+using crypto::apple::Keychain;
 
 #if defined(ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE)
 using KeychainNameContainerType = base::NoDestructor<std::string>;
@@ -51,7 +51,7 @@
 // Generates a random password and adds it to the Keychain.  The added password
 // is returned from the function.  If an error occurs, an empty password is
 // returned.
-std::string AddRandomPasswordToKeychain(const AppleKeychain& keychain,
+std::string AddRandomPasswordToKeychain(const Keychain& keychain,
                                         const std::string& service_name,
                                         const std::string& account_name) {
   // Generate a password with 128 bits of randomness.
@@ -83,7 +83,7 @@
   return *account_name;
 }
 
-KeychainPassword::KeychainPassword(const AppleKeychain& keychain)
+KeychainPassword::KeychainPassword(const Keychain& keychain)
     : keychain_(keychain) {}
 
 KeychainPassword::~KeychainPassword() = default;
diff --git a/components/os_crypt/sync/keychain_password_mac_unittest.mm b/components/os_crypt/sync/keychain_password_mac_unittest.mm
index 8654b66..a7da4ef 100644
--- a/components/os_crypt/sync/keychain_password_mac_unittest.mm
+++ b/components/os_crypt/sync/keychain_password_mac_unittest.mm
@@ -5,12 +5,12 @@
 #include "components/os_crypt/sync/keychain_password_mac.h"
 
 #include "build/build_config.h"
-#include "crypto/mock_apple_keychain.h"
+#include "crypto/apple/mock_keychain.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
-using crypto::MockAppleKeychain;
+using crypto::apple::MockKeychain;
 
 // An environment for KeychainPassword which initializes mock keychain with
 // the given value that is going to be returned when accessing the Keychain.
@@ -24,12 +24,12 @@
   KeychainPasswordEnvironment(KeychainPasswordEnvironment&) = delete;
   KeychainPasswordEnvironment& operator=(KeychainPasswordEnvironment&) = delete;
 
-  MockAppleKeychain& keychain() { return keychain_; }
+  MockKeychain& keychain() { return keychain_; }
 
   std::string GetPassword() const { return keychain_password_->GetPassword(); }
 
  private:
-  MockAppleKeychain keychain_;
+  MockKeychain keychain_;
   std::unique_ptr<KeychainPassword> keychain_password_;
 };
 
diff --git a/components/os_crypt/sync/os_crypt.h b/components/os_crypt/sync/os_crypt.h
index 8ac581bb..a927924 100644
--- a/components/os_crypt/sync/os_crypt.h
+++ b/components/os_crypt/sync/os_crypt.h
@@ -18,8 +18,8 @@
 #include "crypto/subtle_passkey.h"
 
 #if BUILDFLAG(IS_APPLE)
-namespace crypto {
-class AppleKeychain;
+namespace crypto::apple {
+class Keychain;
 }
 #endif
 
@@ -234,7 +234,7 @@
  private:
 #if BUILDFLAG(IS_APPLE)
   // Return the keychain to use for accessing the encryption key.
-  std::unique_ptr<crypto::AppleKeychain> GetKeychain() const;
+  std::unique_ptr<crypto::apple::Keychain> GetKeychain() const;
 
   // Derives an encryption key from data stored in the keychain if necessary.
   // Returns true if there is an encryption key available and false otherwise.
diff --git a/components/os_crypt/sync/os_crypt_mac.mm b/components/os_crypt/sync/os_crypt_mac.mm
index ddb83a8..c4dab9b 100644
--- a/components/os_crypt/sync/os_crypt_mac.mm
+++ b/components/os_crypt/sync/os_crypt_mac.mm
@@ -20,9 +20,9 @@
 #include "components/os_crypt/sync/os_crypt_metrics.h"
 #include "components/os_crypt/sync/os_crypt_switches.h"
 #include "crypto/aes_cbc.h"
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
+#include "crypto/apple/mock_keychain.h"
 #include "crypto/kdf.h"
-#include "crypto/mock_apple_keychain.h"
 #include "crypto/subtle_passkey.h"
 
 namespace os_crypt {
@@ -82,13 +82,13 @@
 OSCryptImpl::OSCryptImpl() = default;
 OSCryptImpl::~OSCryptImpl() = default;
 
-std::unique_ptr<crypto::AppleKeychain> OSCryptImpl::GetKeychain() const {
+std::unique_ptr<crypto::apple::Keychain> OSCryptImpl::GetKeychain() const {
   if (use_mock_keychain_ || base::CommandLine::ForCurrentProcess()->HasSwitch(
                                 os_crypt::switches::kUseMockKeychain)) {
-    return std::make_unique<crypto::MockAppleKeychain>();
+    return std::make_unique<crypto::apple::MockKeychain>();
   }
 
-  return crypto::AppleKeychain::DefaultKeychain();
+  return crypto::apple::Keychain::DefaultKeychain();
 }
 
 bool OSCryptImpl::DeriveKey() {
diff --git a/components/os_crypt/sync/os_crypt_mac_unittest.cc b/components/os_crypt/sync/os_crypt_mac_unittest.cc
index de9df1aa..8f317d9 100644
--- a/components/os_crypt/sync/os_crypt_mac_unittest.cc
+++ b/components/os_crypt/sync/os_crypt_mac_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/strings/string_view_util.h"
 #include "components/os_crypt/sync/os_crypt_mocker.h"
-#include "crypto/mock_apple_keychain.h"
+#include "crypto/apple/mock_keychain.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class OSCryptMacTest : public ::testing::Test {
@@ -38,11 +38,11 @@
   });
 
   // The known answers below were computed using the hardcoded encryption
-  // password supplied by MockAppleKeychain; if that mock password or the key
+  // password supplied by MockKeychain; if that mock password or the key
   // derivation method are ever changed the known answers need to be recomputed.
   // This assert is here to avoid having a difficult-to-debug decryption failure
   // later in the test in this case.
-  ASSERT_EQ(crypto::MockAppleKeychain().GetEncryptionPassword(),
+  ASSERT_EQ(crypto::apple::MockKeychain().GetEncryptionPassword(),
             "mock_password")
       << "Mock keychain password is different than expected. If you changed it,"
          " you need to recompute the known answers in this test.";
diff --git a/components/page_content_annotations/core/page_content_annotations_features.cc b/components/page_content_annotations/core/page_content_annotations_features.cc
index 3a3ee65..e856f9ec 100644
--- a/components/page_content_annotations/core/page_content_annotations_features.cc
+++ b/components/page_content_annotations/core/page_content_annotations_features.cc
@@ -38,20 +38,6 @@
     base::FEATURE_ENABLED_BY_DEFAULT;
 #endif
 
-constexpr char enabled_all_mobile_locales_en_us_desktop_only[] =
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-    "*";
-#else
-    "en-US";
-#endif
-
-constexpr char enabled_all_mobile_countries_us_desktop_only[] =
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-    "*";
-#else
-    "us";
-#endif
-
 // Returns whether |locale| is a supported locale for |feature|.
 //
 // This matches |locale| with the "supported_locales" feature param value in
@@ -151,7 +137,7 @@
 // Enables fetching page metadata from the remote Optimization Guide service.
 BASE_FEATURE(kRemotePageMetadata,
              "RemotePageMetadata",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             enabled_by_default_desktop_only);
 
 BASE_FEATURE(kOptimizationGuideUseContinueOnShutdownForPageContentAnnotations,
              "OptimizationGuideUseContinueOnShutdownForPageContentAnnotations",
@@ -159,7 +145,7 @@
 
 BASE_FEATURE(kPageContentAnnotationsPersistSalientImageMetadata,
              "PageContentAnnotationsPersistSalientImageMetadata",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             enabled_by_default_desktop_only);
 
 BASE_FEATURE(kExtractRelatedSearchesFromPrefetchedZPSResponse,
              "ExtractRelatedSearchesFromPrefetchedZPSResponse",
@@ -217,12 +203,8 @@
 bool RemotePageMetadataEnabled(const std::string& locale,
                                const std::string& country_code) {
   return base::FeatureList::IsEnabled(kRemotePageMetadata) &&
-         IsSupportedLocaleForFeature(
-             locale, kRemotePageMetadata,
-             enabled_all_mobile_locales_en_us_desktop_only) &&
-         IsSupportedCountryForFeature(
-             country_code, kRemotePageMetadata,
-             enabled_all_mobile_countries_us_desktop_only);
+         IsSupportedLocaleForFeature(locale, kRemotePageMetadata, "en-US") &&
+         IsSupportedCountryForFeature(country_code, kRemotePageMetadata, "us");
 }
 
 int GetMinimumPageCategoryScoreToPersist() {
@@ -285,10 +267,10 @@
              kPageContentAnnotationsPersistSalientImageMetadata) &&
          IsSupportedLocaleForFeature(
              locale, kPageContentAnnotationsPersistSalientImageMetadata,
-             enabled_all_mobile_locales_en_us_desktop_only) &&
+             "en-US") &&
          IsSupportedCountryForFeature(
              country_code, kPageContentAnnotationsPersistSalientImageMetadata,
-             enabled_all_mobile_countries_us_desktop_only);
+             "us");
 }
 
 size_t MaxRelatedSearchesCacheSize() {
diff --git a/components/page_content_annotations/core/page_content_annotations_features_unittest.cc b/components/page_content_annotations/core/page_content_annotations_features_unittest.cc
index 7ccdb208..b9c7a99 100644
--- a/components/page_content_annotations/core/page_content_annotations_features_unittest.cc
+++ b/components/page_content_annotations/core/page_content_annotations_features_unittest.cc
@@ -74,19 +74,6 @@
   EXPECT_FALSE(features::RemotePageMetadataEnabled("badlocale", "US"));
 }
 
-TEST(OptimizationGuideFeaturesTest, RemotePageMetadataEnabledWildcard) {
-  base::test::ScopedFeatureList scoped_feature_list;
-
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      features::kRemotePageMetadata,
-      {{"supported_locales", "*"}, {"supported_countries", "*"}});
-
-  EXPECT_TRUE(features::RemotePageMetadataEnabled("en-US", "CA"));
-  EXPECT_TRUE(features::RemotePageMetadataEnabled("", ""));
-  EXPECT_TRUE(features::RemotePageMetadataEnabled("en-US", "badcountry"));
-  EXPECT_TRUE(features::RemotePageMetadataEnabled("badlocale", "US"));
-}
-
 TEST(OptimizationGuideFeaturesTest,
      ShouldExecutePageVisibilityModelOnPageContentWithAllowlist) {
   base::test::ScopedFeatureList scoped_feature_list;
diff --git a/components/page_content_annotations/core/page_content_annotations_service_unittest.cc b/components/page_content_annotations/core/page_content_annotations_service_unittest.cc
index d488162d..8901f38 100644
--- a/components/page_content_annotations/core/page_content_annotations_service_unittest.cc
+++ b/components/page_content_annotations/core/page_content_annotations_service_unittest.cc
@@ -398,9 +398,7 @@
     : public PageContentAnnotationsServiceTest {
  public:
   PageContentAnnotationsServiceRemotePageMetadataTest() {
-    scoped_feature_list_.InitAndEnableFeatureWithParameters(
-    features::kRemotePageMetadata,
-    {{"supported_locales", "*"}, {"supported_countries", "*"}});
+    scoped_feature_list_.InitAndEnableFeature(features::kRemotePageMetadata);
   }
 
  private:
@@ -443,9 +441,8 @@
     : public PageContentAnnotationsServiceTest {
  public:
   PageContentAnnotationsServiceSalientImageMetadataTest() {
-    scoped_feature_list_.InitAndEnableFeatureWithParameters(
-      features::kPageContentAnnotationsPersistSalientImageMetadata,
-      {{"supported_locales", "*"}, {"supported_countries", "*"}});
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kPageContentAnnotationsPersistSalientImageMetadata);
   }
 
  private:
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index 5b34cd4..9f310d2 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -19,6 +19,7 @@
 #include "components/page_load_metrics/browser/page_load_tracker.h"
 #include "components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h"
 #include "components/page_load_metrics/common/page_load_metrics.mojom.h"
+#include "components/page_load_metrics/common/page_load_timing.h"
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -33,11 +34,11 @@
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h"
 #include "third_party/blink/public/mojom/use_counter/use_counter_feature.mojom-shared.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "url/url_constants.h"
 
 using content::NavigationSimulator;
@@ -129,10 +130,7 @@
         std::vector<mojom::ResourceDataUpdatePtr>(),
         mojom::FrameRenderDataUpdatePtr(std::in_place), timing.Clone(),
         mojom::InputTimingPtr(std::in_place), std::nullopt,
-        mojom::SoftNavigationMetrics::New(
-            blink::kSoftNavigationCountDefaultValue, base::Milliseconds(0),
-            blink::kNavigationIdDefaultValue,
-            mojom::LargestContentfulPaintTiming::New()));
+        CreateSoftNavigationMetrics());
   }
 
   void SimulateTimingUpdate(const mojom::PageLoadTiming& timing,
@@ -158,10 +156,7 @@
         mojom::FrameRenderDataUpdatePtr(std::in_place),
         mojom::CpuTimingPtr(std::in_place),
         mojom::InputTimingPtr(std::in_place), std::nullopt,
-        mojom::SoftNavigationMetrics::New(
-            blink::kSoftNavigationCountDefaultValue, base::Milliseconds(0),
-            blink::kNavigationIdDefaultValue,
-            mojom::LargestContentfulPaintTiming::New()));
+        CreateSoftNavigationMetrics());
   }
 
   void SimulateCustomUserTimingUpdate(
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h
index 3da8648..e7f72353 100644
--- a/components/page_load_metrics/browser/page_load_tracker.h
+++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -27,7 +27,6 @@
 #include "net/cookies/canonical_cookie.h"
 #include "services/metrics/public/cpp/ukm_source.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "ui/base/scoped_visibility_tracker.h"
 #include "ui/gfx/geometry/size.h"
 
diff --git a/components/page_load_metrics/common/page_load_timing.cc b/components/page_load_metrics/common/page_load_timing.cc
index 3a70d960..c2c10fd 100644
--- a/components/page_load_metrics/common/page_load_timing.cc
+++ b/components/page_load_metrics/common/page_load_timing.cc
@@ -4,7 +4,7 @@
 
 #include "components/page_load_metrics/common/page_load_timing.h"
 #include "components/page_load_metrics/common/page_load_metrics.mojom-forward.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 
 namespace page_load_metrics {
 
@@ -32,8 +32,7 @@
 
 mojom::SoftNavigationMetricsPtr CreateSoftNavigationMetrics() {
   return mojom::SoftNavigationMetrics::New(
-      blink::kSoftNavigationCountDefaultValue, base::Milliseconds(0),
-      blink::kNavigationIdDefaultValue, CreateLargestContentfulPaintTiming());
+      0, base::Milliseconds(0), 0, CreateLargestContentfulPaintTiming());
 }
 
 bool IsEmpty(const page_load_metrics::mojom::DocumentTiming& timing) {
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
index 0d1ac40b..c85a952f 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -183,7 +183,7 @@
 }
 
 void MetricsRenderFrameObserver::DidObserveSoftNavigation(
-    blink::SoftNavigationMetrics soft_nav_metrics) {
+    blink::SoftNavigationMetricsForReporting soft_nav_metrics) {
   if (page_timing_metrics_sender_) {
     const blink::WebPerformanceMetricsForReporting& metrics =
         render_frame()->GetWebFrame()->PerformanceMetricsForReporting();
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/components/page_load_metrics/renderer/metrics_render_frame_observer.h
index 2563f85..d77dcb9 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer.h
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer.h
@@ -92,7 +92,8 @@
       const blink::SubresourceLoadMetrics& subresource_load_metrics) override;
   void DidObserveNewFeatureUsage(
       const blink::UseCounterFeature& feature) override;
-  void DidObserveSoftNavigation(blink::SoftNavigationMetrics metrics) override;
+  void DidObserveSoftNavigation(
+      blink::SoftNavigationMetricsForReporting metrics) override;
   void DidObserveLayoutShift(double score, bool after_input_or_scroll) override;
   void DidStartResponse(const url::SchemeHostPort& final_response_url,
                         int request_id,
diff --git a/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc b/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
index 093bfafd..395e0b5 100644
--- a/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
+++ b/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc
@@ -102,10 +102,7 @@
   FakePageTimingSender::PageTimingValidator validator_;
   mutable mojom::PageLoadTimingPtr fake_timing_;
   mojom::SoftNavigationMetricsPtr fake_soft_navigation_metrics_ =
-      mojom::SoftNavigationMetrics::New(blink::kSoftNavigationCountDefaultValue,
-                                        base::Milliseconds(0),
-                                        blink::kNavigationIdDefaultValue,
-                                        CreateLargestContentfulPaintTiming());
+      CreateSoftNavigationMetrics();
 };
 
 typedef testing::Test MetricsRenderFrameObserverTest;
@@ -194,10 +191,7 @@
   mojom::PageLoadTiming timing;
   page_load_metrics::InitPageLoadTimingForTest(&timing);
   mojom::SoftNavigationMetricsPtr soft_navigation_metrics =
-      mojom::SoftNavigationMetrics::New(blink::kSoftNavigationCountDefaultValue,
-                                        base::Milliseconds(0),
-                                        blink::kNavigationIdDefaultValue,
-                                        CreateLargestContentfulPaintTiming());
+      CreateSoftNavigationMetrics();
   timing.navigation_start = nav_start;
   observer.ExpectPageLoadTiming(timing);
   observer.ExpectSoftNavigationMetrics(*soft_navigation_metrics);
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
index 6a516bf..8bbe941 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -125,7 +125,7 @@
 }
 
 void PageTimingMetricsSender::DidObserveSoftNavigation(
-    blink::SoftNavigationMetrics new_metrics) {
+    blink::SoftNavigationMetricsForReporting new_metrics) {
   // The start_time is a TimeDelta, and its resolution is in microseconds.
   // Every time we observe a new soft navigation we expect the total count to
   // increase by one, and the navigation_id to update, however, we have no
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
index 81b5297..ad738f2 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender.h
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender.h
@@ -36,7 +36,7 @@
 }  // namespace network
 
 namespace blink {
-struct SoftNavigationMetrics;
+struct SoftNavigationMetricsForReporting;
 }  // namespace blink
 
 namespace page_load_metrics {
@@ -67,7 +67,8 @@
   void DidObserveSubresourceLoad(
       const blink::SubresourceLoadMetrics& subresource_load_metrics);
   void DidObserveNewFeatureUsage(const blink::UseCounterFeature& feature);
-  void DidObserveSoftNavigation(blink::SoftNavigationMetrics metrics);
+  void DidObserveSoftNavigation(
+      blink::SoftNavigationMetricsForReporting metrics);
   void DidObserveLayoutShift(double score, bool after_input_or_scroll);
 
   void DidStartResponse(const url::SchemeHostPort& final_response_url,
diff --git a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
index dce52f8..a6a8c45 100644
--- a/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
+++ b/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
+#include "components/page_load_metrics/common/page_load_timing.h"
 #include "components/page_load_metrics/common/page_load_metrics.mojom.h"
 #include "components/page_load_metrics/renderer/fake_page_timing_sender.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -45,10 +46,8 @@
             CreatePageLoadTiming(),
             PageTimingMetadataRecorder::MonotonicTiming())) {}
 
-  mojom::SoftNavigationMetrics CreateEmptySoftNavigationMetrics() {
-    return mojom::SoftNavigationMetrics(
-        blink::kSoftNavigationCountDefaultValue, base::Milliseconds(0),
-        blink::kNavigationIdDefaultValue, CreateLargestContentfulPaintTiming());
+  mojom::SoftNavigationMetricsPtr CreateEmptySoftNavigationMetrics() {
+    return CreateSoftNavigationMetrics();
   }
 
  protected:
@@ -68,7 +67,7 @@
 
   // Firing the timer should trigger sending of an SendTiming call.
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
   ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
   metrics_sender_->mock_timer()->Fire();
   EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
@@ -104,7 +103,7 @@
   // Firing the timer should trigger sending of the SendTiming call with
   // the most recently provided PageLoadTiming instance.
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
   metrics_sender_->mock_timer()->Fire();
   EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
 }
@@ -121,7 +120,7 @@
                           PageTimingMetadataRecorder::MonotonicTiming());
   ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
   metrics_sender_->mock_timer()->Fire();
   EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
   validator_.VerifyExpectedTimings();
@@ -133,7 +132,7 @@
                           PageTimingMetadataRecorder::MonotonicTiming());
   ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
   metrics_sender_->mock_timer()->Fire();
   EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
 }
@@ -149,7 +148,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
   ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
 
   metrics_sender_->SendLatest();
@@ -161,7 +160,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   blink::SubresourceLoadMetrics metrics{
       .number_of_subresources_loaded = 5,
@@ -187,7 +186,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   // Observe a single feature, update expected features sent across IPC.
   metrics_sender_->DidObserveNewFeatureUsage(feature);
@@ -212,7 +211,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   // Observe the first feature, update expected features sent across IPC.
   metrics_sender_->DidObserveNewFeatureUsage(feature_0);
@@ -240,7 +239,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   metrics_sender_->DidObserveNewFeatureUsage(feature);
   validator_.UpdateExpectPageLoadFeatures(feature);
@@ -267,7 +266,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   // Observe the first feature, update expected features sent across IPC.
   metrics_sender_->DidObserveNewFeatureUsage(feature_0);
@@ -289,7 +288,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
   // Observe duplicated feature usage, without updating expected features sent
   // across IPC.
   metrics_sender_->DidObserveNewFeatureUsage(feature_0);
@@ -317,7 +316,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   metrics_sender_->DidObserveLayoutShift(0.5, false);
   metrics_sender_->DidObserveLayoutShift(0.5, false);
@@ -336,7 +335,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   metrics_sender_->OnMainFrameIntersectionChanged(gfx::Rect(0, 0, 1, 1));
   validator_.UpdateExpectedMainFrameIntersectionRect(gfx::Rect(0, 0, 1, 1));
@@ -351,7 +350,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   metrics_sender_->OnMainFrameViewportRectangleChanged(gfx::Rect(2, 2, 1, 1));
   validator_.UpdateExpectedMainFrameViewportRect(gfx::Rect(2, 2, 1, 1));
@@ -377,7 +376,7 @@
   metrics_sender_->Update(timing.Clone(),
                           PageTimingMetadataRecorder::MonotonicTiming());
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   // max_event_queued and max_event_commit_finish is irrelevant to this test.
   metrics_sender_->DidObserveUserInteraction(
@@ -403,7 +402,7 @@
   InitPageLoadTimingForTest(&timing);
   timing.paint_timing->first_contentful_paint = base::Seconds(1);
   validator_.ExpectPageLoadTiming(timing);
-  validator_.ExpectSoftNavigationMetrics(CreateEmptySoftNavigationMetrics());
+  validator_.ExpectSoftNavigationMetrics(*CreateEmptySoftNavigationMetrics());
 
   // Updating when |timing| has FCP will cause the metrics to be sent urgently.
   metrics_sender_->Update(timing.Clone(),
diff --git a/components/password_manager/core/browser/features/password_manager_features_util.cc b/components/password_manager/core/browser/features/password_manager_features_util.cc
index 745eb6a..9c7afaff 100644
--- a/components/password_manager/core/browser/features/password_manager_features_util.cc
+++ b/components/password_manager/core/browser/features/password_manager_features_util.cc
@@ -27,8 +27,7 @@
 
 namespace {
 
-bool IsUserEligibleForAccountStorage(const PrefService* pref_service,
-                                     const syncer::SyncService* sync_service) {
+bool IsUserEligibleForAccountStorage(const syncer::SyncService* sync_service) {
   if (!sync_service) {
     return false;
   }
@@ -79,56 +78,19 @@
     return false;
   }
 
-  // Check last to avoid tests for signed-out users unnecessarily having to
-  // register some prefs to avoid a crash.
-  return CanCreateAccountStore(pref_service);
+  return true;
 }
 
 }  // namespace
 
-bool CanCreateAccountStore(const PrefService* pref_service) {
-#if BUILDFLAG(IS_ANDROID)
-  if (base::FeatureList::IsEnabled(features::kLoginDbDeprecationAndroid)) {
-    // The login DB deprecation stops migrations to UPM, so the migration
-    // status becomes irrelevant. Depending on the GMS Core version, the account
-    // store might be backed by an empty backend instead of a real one,
-    // but it can be created nonetheless.
-    return true;
-  }
-  using prefs::UseUpmLocalAndSeparateStoresState;
-  switch (
-      static_cast<UseUpmLocalAndSeparateStoresState>(pref_service->GetInteger(
-          prefs::kPasswordsUseUPMLocalAndSeparateStores))) {
-    case UseUpmLocalAndSeparateStoresState::kOff:
-      return false;
-    // The decision regarding the presence/absence of the account store happens
-    // before the outcome of the migration is known. The decision shouldn't
-    // change, many layers cache a pointer to the store and never update it.
-    // The solution is to optimistically return true in the "migration pending"
-    // state. If the migration later fails, the store will continue to exist
-    // until the next restart, but won't actually be used (this is enforced by
-    // other predicates).
-    case UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending:
-    case UseUpmLocalAndSeparateStoresState::kOn:
-      return true;
-  }
-  NOTREACHED();
-#else
-  return true;
-#endif
-}
-
-bool IsAccountStorageEnabled(const PrefService* pref_service,
-                             const syncer::SyncService* sync_service) {
-  return IsUserEligibleForAccountStorage(pref_service, sync_service) &&
+bool IsAccountStorageEnabled(const syncer::SyncService* sync_service) {
+  return IsUserEligibleForAccountStorage(sync_service) &&
          sync_service->GetUserSettings()->GetSelectedTypes().Has(
              syncer::UserSelectableType::kPasswords);
 }
 
 PasswordAccountStorageUserState ComputePasswordAccountStorageUserState(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service) {
-  DCHECK(pref_service);
   // The SyncService can be null in incognito, or due to a commandline flag. In
   // those cases, simply consider the user as signed out.
   if (!sync_service) {
@@ -146,7 +108,7 @@
     return PasswordAccountStorageUserState::kSignedOutUser;
   }
 
-  if (IsAccountStorageEnabled(pref_service, sync_service)) {
+  if (IsAccountStorageEnabled(sync_service)) {
     return PasswordAccountStorageUserState::kSignedInAccountStoreUser;
   }
 
@@ -154,11 +116,10 @@
 }
 
 PasswordAccountStorageUsageLevel ComputePasswordAccountStorageUsageLevel(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service) {
   using UserState = PasswordAccountStorageUserState;
   using UsageLevel = PasswordAccountStorageUsageLevel;
-  switch (ComputePasswordAccountStorageUserState(pref_service, sync_service)) {
+  switch (ComputePasswordAccountStorageUserState(sync_service)) {
     case UserState::kSignedOutUser:
     case UserState::kSignedInUser:
       return UsageLevel::kNotUsingAccountStorage;
@@ -171,12 +132,11 @@
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 bool ShouldShowAccountStorageSettingToggle(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service) {
   // TODO(crbug.com/303613699): Merge IsUserEligibleForAccountStorage() and
   // IsAccountStorageEnabled() after kReplaceSyncPromosWithSignInPromos is
   // launched and cleaned-up.
-  return IsUserEligibleForAccountStorage(pref_service, sync_service) &&
+  return IsUserEligibleForAccountStorage(sync_service) &&
          !base::FeatureList::IsEnabled(
              syncer::kReplaceSyncPromosWithSignInPromos);
 }
diff --git a/components/password_manager/core/browser/features/password_manager_features_util.h b/components/password_manager/core/browser/features/password_manager_features_util.h
index cd32c78..49053ed 100644
--- a/components/password_manager/core/browser/features/password_manager_features_util.h
+++ b/components/password_manager/core/browser/features/password_manager_features_util.h
@@ -45,43 +45,30 @@
   kSyncing = 2,
 };
 
-// Whether to instantiate a second PasswordStore whose data is account-scoped.
-// This doesn't necessarily mean the store is being used, e.g. this predicate
-// can return true for a signed-out user. For whether the store can be used,
-// see IsAccountStorageEnabled() instead.
-// On Android, if the internal backend is not present (i.e. in a public build),
-// this method will return true, but the store itself will not be created.
-bool CanCreateAccountStore(const PrefService* pref_service);
-
 // Whether the Google account storage for passwords is enabled for the current
 // signed-in user. This always returns false for sync-the-feature users and
 // signed out users. Account storage can be enabled/disabled via
 // syncer::SyncUserSettings::SetSelectedType().
 //
-// |pref_service| must not be null.
 // |sync_service| may be null (commonly the case in incognito mode), in which
 // case this will simply return false.
 // See PasswordFeatureManager::IsAccountStorageEnabled.
-bool IsAccountStorageEnabled(const PrefService* pref_service,
-                             const syncer::SyncService* sync_service);
+bool IsAccountStorageEnabled(const syncer::SyncService* sync_service);
 
 // See definition of PasswordAccountStorageUserState.
 PasswordAccountStorageUserState ComputePasswordAccountStorageUserState(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service);
 
 // Returns the "usage level" of the account-scoped password storage. See
 // definition of PasswordAccountStorageUsageLevel.
 // See PasswordFeatureManager::ComputePasswordAccountStorageUsageLevel.
 PasswordAccountStorageUsageLevel ComputePasswordAccountStorageUsageLevel(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service);
 
 #if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
 
 // Whether the user toggle for account storage is shown in settings.
 bool ShouldShowAccountStorageSettingToggle(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service);
 
 // Users with account storage enabled used to have the choice of saving new
diff --git a/components/password_manager/core/browser/features/password_manager_features_util_unittest.cc b/components/password_manager/core/browser/features/password_manager_features_util_unittest.cc
index 94cedaa..dbfa0a6 100644
--- a/components/password_manager/core/browser/features/password_manager_features_util_unittest.cc
+++ b/components/password_manager/core/browser/features/password_manager_features_util_unittest.cc
@@ -27,13 +27,7 @@
 
 class PasswordManagerFeaturesUtilTest : public testing::Test {
  public:
-  PasswordManagerFeaturesUtilTest() {
-#if BUILDFLAG(IS_ANDROID)
-    pref_service_.registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-#endif
-  }
+  PasswordManagerFeaturesUtilTest() = default;
 
   PasswordManagerFeaturesUtilTest(const PasswordManagerFeaturesUtilTest&) =
       delete;
@@ -43,14 +37,13 @@
   ~PasswordManagerFeaturesUtilTest() override = default;
 
  protected:
-  TestingPrefServiceSimple pref_service_;
   syncer::TestSyncService sync_service_;
 };
 
 TEST_F(PasswordManagerFeaturesUtilTest, IsAccountStorageEnabled_SignedOut) {
   sync_service_.SetSignedOut();
 
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_FALSE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
@@ -58,7 +51,7 @@
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
   sync_service_.SetLocalSyncEnabled(true);
 
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_FALSE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
@@ -66,7 +59,7 @@
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
   sync_service_.SetPersistentAuthError();
 
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_FALSE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
@@ -74,7 +67,7 @@
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
   sync_service_.SetPassphraseRequired();
 
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_FALSE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
@@ -82,7 +75,7 @@
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
   sync_service_.SetTrustedVaultKeyRequired(true);
 
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_FALSE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
@@ -91,71 +84,22 @@
   sync_service_.GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, false);
 
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_FALSE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
        IsAccountStorageEnabled_SignedInHealthy) {
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
 
-  EXPECT_TRUE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
+  EXPECT_TRUE(IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest, IsAccountStorageEnabled_Syncing) {
   sync_service_.SetSignedIn(signin::ConsentLevel::kSync);
 
-  EXPECT_EQ(IsAccountStorageEnabled(&pref_service_, &sync_service_),
-            BUILDFLAG(IS_ANDROID));
+  EXPECT_EQ(IsAccountStorageEnabled(&sync_service_), BUILDFLAG(IS_ANDROID));
 }
 
-#if BUILDFLAG(IS_ANDROID)
-TEST_F(PasswordManagerFeaturesUtilTest,
-       CanCreateAccountStore_LoginDbDeprecationOff) {
-  using enum prefs::UseUpmLocalAndSeparateStoresState;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kLoginDbDeprecationAndroid);
-  sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
-
-  EXPECT_TRUE(CanCreateAccountStore(&pref_service_));
-  EXPECT_TRUE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
-
-  pref_service_.SetInteger(prefs::kPasswordsUseUPMLocalAndSeparateStores,
-                           static_cast<int>(kOffAndMigrationPending));
-
-  EXPECT_TRUE(CanCreateAccountStore(&pref_service_));
-  EXPECT_TRUE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
-
-  pref_service_.SetInteger(prefs::kPasswordsUseUPMLocalAndSeparateStores,
-                           static_cast<int>(kOff));
-
-  EXPECT_FALSE(CanCreateAccountStore(&pref_service_));
-  EXPECT_FALSE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
-}
-
-TEST_F(PasswordManagerFeaturesUtilTest,
-       CanCreateAccountStore_LoginDbDeprecationOn) {
-  using enum prefs::UseUpmLocalAndSeparateStoresState;
-  base::test::ScopedFeatureList feature_list(
-      features::kLoginDbDeprecationAndroid);
-  sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
-
-  EXPECT_TRUE(CanCreateAccountStore(&pref_service_));
-  EXPECT_TRUE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
-
-  pref_service_.SetInteger(prefs::kPasswordsUseUPMLocalAndSeparateStores,
-                           static_cast<int>(kOffAndMigrationPending));
-
-  EXPECT_TRUE(CanCreateAccountStore(&pref_service_));
-  EXPECT_TRUE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
-
-  pref_service_.SetInteger(prefs::kPasswordsUseUPMLocalAndSeparateStores,
-                           static_cast<int>(kOff));
-
-  EXPECT_TRUE(CanCreateAccountStore(&pref_service_));
-  EXPECT_TRUE(IsAccountStorageEnabled(&pref_service_, &sync_service_));
-}
-#endif
-
 #if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
 TEST_F(PasswordManagerFeaturesUtilTest,
        ShouldShowAccountStorageSettingToggle_SyncToSigninOff) {
@@ -164,8 +108,7 @@
       syncer::kReplaceSyncPromosWithSignInPromos);
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
 
-  EXPECT_TRUE(
-      ShouldShowAccountStorageSettingToggle(&pref_service_, &sync_service_));
+  EXPECT_TRUE(ShouldShowAccountStorageSettingToggle(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest,
@@ -174,21 +117,20 @@
       syncer::kReplaceSyncPromosWithSignInPromos);
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin);
 
-  EXPECT_FALSE(
-      ShouldShowAccountStorageSettingToggle(&pref_service_, &sync_service_));
+  EXPECT_FALSE(ShouldShowAccountStorageSettingToggle(&sync_service_));
 }
 
 TEST_F(PasswordManagerFeaturesUtilTest, MigrateDefaultProfileStorePref) {
+  TestingPrefServiceSimple pref_service;
   // GetSelectedTypesForAccount may check some prefs in SignInPrefs. Ensure that
   // they are registered for this test.
-  SigninPrefs::RegisterProfilePrefs(pref_service_.registry());
-
-  syncer::SyncPrefs::RegisterProfilePrefs(pref_service_.registry());
-  pref_service_.registry()->RegisterDictionaryPref(
+  SigninPrefs::RegisterProfilePrefs(pref_service.registry());
+  syncer::SyncPrefs::RegisterProfilePrefs(pref_service.registry());
+  pref_service.registry()->RegisterDictionaryPref(
       prefs::kObsoleteAccountStoragePerAccountSettings);
-  pref_service_.registry()->RegisterBooleanPref(::prefs::kExplicitBrowserSignin,
-                                                false);
-  pref_service_.registry()->RegisterBooleanPref(
+  pref_service.registry()->RegisterBooleanPref(::prefs::kExplicitBrowserSignin,
+                                               false);
+  pref_service.registry()->RegisterBooleanPref(
       ::prefs::kPrefsThemesSearchEnginesAccountStorageEnabled, false);
 
   // Set up 2 account storage users, with default stores "profile" and
@@ -199,12 +141,12 @@
       signin::GaiaIdHash::FromGaiaId(profile_store_user_gaia);
   auto account_store_user_hash =
       signin::GaiaIdHash::FromGaiaId(account_store_user_gaia);
-  syncer::SyncPrefs sync_prefs(&pref_service_);
+  syncer::SyncPrefs sync_prefs(&pref_service);
   sync_prefs.SetSelectedTypeForAccount(syncer::UserSelectableType::kPasswords,
                                        true, profile_store_user_gaia);
   sync_prefs.SetSelectedTypeForAccount(syncer::UserSelectableType::kPasswords,
                                        true, account_store_user_gaia);
-  pref_service_.SetDict(
+  pref_service.SetDict(
       prefs::kObsoleteAccountStoragePerAccountSettings,
       base::Value::Dict()
           .Set(profile_store_user_hash.ToBase64(),
@@ -223,7 +165,7 @@
   EXPECT_TRUE(sync_prefs.GetSelectedTypesForAccount(account_store_user_gaia)
                   .Has(syncer::UserSelectableType::kPasswords));
 
-  MigrateDefaultProfileStorePref(&pref_service_);
+  MigrateDefaultProfileStorePref(&pref_service);
 
   // After the migration, account storage will be off for the user with profile
   // store as the default.
diff --git a/components/password_manager/core/browser/manage_passwords_referrer.h b/components/password_manager/core/browser/manage_passwords_referrer.h
index cd8aa9b9..183e903 100644
--- a/components/password_manager/core/browser/manage_passwords_referrer.h
+++ b/components/password_manager/core/browser/manage_passwords_referrer.h
@@ -111,7 +111,7 @@
 
   // The warning (Android only) informs the user that they may loose access to
   // their passwords because the transition to UPM has not happened.
-  kAccessLossWarning = 27,
+  // Deprecated: kAccessLossWarning = 27,
 
   // The bubble that notifies the user that a passkey was created automatically
   // in GPM to upgrade an existing, matching password credential.
diff --git a/components/password_manager/core/browser/password_feature_manager_impl.cc b/components/password_manager/core/browser/password_feature_manager_impl.cc
index 3d7af09..d1116ef 100644
--- a/components/password_manager/core/browser/password_feature_manager_impl.cc
+++ b/components/password_manager/core/browser/password_feature_manager_impl.cc
@@ -65,13 +65,12 @@
 }
 
 bool PasswordFeatureManagerImpl::IsAccountStorageEnabled() const {
-  return features_util::IsAccountStorageEnabled(pref_service_, sync_service_);
+  return features_util::IsAccountStorageEnabled(sync_service_);
 }
 
 features_util::PasswordAccountStorageUsageLevel
 PasswordFeatureManagerImpl::ComputePasswordAccountStorageUsageLevel() const {
-  return features_util::ComputePasswordAccountStorageUsageLevel(pref_service_,
-                                                                sync_service_);
+  return features_util::ComputePasswordAccountStorageUsageLevel(sync_service_);
 }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 6766fd51..3a16213 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -529,10 +529,8 @@
   registry->RegisterBooleanPref(prefs::kOfferToSavePasswordsEnabledGMS, true);
   registry->RegisterBooleanPref(prefs::kAccountStorageNoticeShown, false);
   registry->RegisterBooleanPref(prefs::kAutoSignInEnabledGMS, true);
-  registry->RegisterBooleanPref(prefs::kSettingsMigratedToUPMLocal, false);
   registry->RegisterIntegerPref(
       prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
-  registry->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt, 0.0);
   registry->RegisterIntegerPref(
       prefs::kPasswordsUseUPMLocalAndSeparateStores,
       static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOff));
@@ -549,10 +547,6 @@
   // passwords might be left behind. In practice, the default value should make
   // little difference, the pref is always written on startup.
   registry->RegisterBooleanPref(prefs::kEmptyProfileStoreLoginDatabase, false);
-  registry->RegisterTimePref(
-      prefs::kPasswordAccessLossWarningShownAtStartupTimestamp, base::Time());
-  registry->RegisterTimePref(prefs::kPasswordAccessLossWarningShownTimestamp,
-                             base::Time());
   registry->RegisterBooleanPref(prefs::kUpmAutoExportCsvNeedsDeletion, false);
   registry->RegisterBooleanPref(prefs::kUpmUnmigratedPasswordsExported, false);
 #endif  // BUILDFLAG(IS_ANDROID)
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.cc b/components/password_manager/core/browser/password_manager_metrics_util.cc
index 74ca063d..41451a25 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -517,14 +517,6 @@
 }
 
 #if BUILDFLAG(IS_ANDROID)
-void LogLocalPwdMigrationProgressState(
-    LocalPwdMigrationProgressState scheduling_state) {
-  base::UmaHistogramEnumeration(
-      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
-      "ProgressState",
-      scheduling_state);
-}
-
 void LogSharedPrefCredentialsAccessOutcome(
     SharedPrefCredentialsAccessOutcome outcome) {
   base::UmaHistogramEnumeration(
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 adef980..fe493dc0 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -563,17 +563,6 @@
 // LINT.ThenChange(/tools/metrics/histograms/metadata/password/enums.xml:PasswordChangeFlowStep)
 
 #if BUILDFLAG(IS_ANDROID)
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused. Keep in sync with `
-// `LocalPwdMigrationProgressState` in the passwords' enums.xml.
-enum class LocalPwdMigrationProgressState {
-  kScheduled = 0,
-  kStarted = 1,
-  // Finished is recorded irrespective of success status.
-  kFinished = 2,
-  kMaxValue = kFinished,
-};
-
 // Enum specifying the outcome of an attempt to access credentials stored in a
 // SharedPref. These values are persisted to logs. Entries should not be
 // renumbered and numeric values should never be reused. Keep in sync with
@@ -813,13 +802,6 @@
 void LogProcessIncomingPasswordSharingInvitationResult(
     ProcessIncomingPasswordSharingInvitationResult result);
 
-#if BUILDFLAG(IS_ANDROID)
-// Records the scheduling state of the local passwords migration to the
-// Android backend.
-void LogLocalPwdMigrationProgressState(
-    LocalPwdMigrationProgressState scheduling_state);
-#endif
-
 // Wraps |callback| into another callback that measures the elapsed time between
 // construction and actual execution of the callback. Records the result to
 // |histogram|, which is expected to be a char literal.
diff --git a/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc b/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
index edb3a21..1e286ada 100644
--- a/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
+++ b/components/password_manager/core/browser/password_session_durations_metrics_recorder.cc
@@ -25,14 +25,10 @@
 }  // namespace
 
 PasswordSessionDurationsMetricsRecorder::
-    PasswordSessionDurationsMetricsRecorder(PrefService* pref_service,
-                                            syncer::SyncService* sync_service)
-    : pref_service_(pref_service),
-      sync_service_(sync_service),
+    PasswordSessionDurationsMetricsRecorder(syncer::SyncService* sync_service)
+    : sync_service_(sync_service),
       user_state_(features_util::ComputePasswordAccountStorageUserState(
-          pref_service_,
           sync_service_)) {
-  DCHECK(pref_service_);
   // |sync_service| can be null if sync is disabled by a command line flag.
   if (sync_service_) {
     sync_observation_.Observe(sync_service_.get());
@@ -88,8 +84,7 @@
 
 void PasswordSessionDurationsMetricsRecorder::CheckForUserStateChange() {
   features_util::PasswordAccountStorageUserState new_user_state =
-      features_util::ComputePasswordAccountStorageUserState(pref_service_,
-                                                            sync_service_);
+      features_util::ComputePasswordAccountStorageUserState(sync_service_);
   // If the state is unchanged, nothing to do.
   if (new_user_state == user_state_) {
     return;
diff --git a/components/password_manager/core/browser/password_session_durations_metrics_recorder.h b/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
index 10c1e34..46a2599 100644
--- a/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
+++ b/components/password_manager/core/browser/password_session_durations_metrics_recorder.h
@@ -18,8 +18,6 @@
 class SyncService;
 }  // namespace syncer
 
-class PrefService;
-
 namespace password_manager {
 
 // Tracks the active browsing time that the user spends in each state related to
@@ -27,11 +25,10 @@
 class PasswordSessionDurationsMetricsRecorder
     : public syncer::SyncServiceObserver {
  public:
-  // |pref_service| must not be null and must outlive this object.
   // |sync_service| may be null (in incognito profiles or due to a commandline
   // flag), but if non-null must outlive this object.
-  PasswordSessionDurationsMetricsRecorder(PrefService* pref_service,
-                                          syncer::SyncService* sync_service);
+  explicit PasswordSessionDurationsMetricsRecorder(
+      syncer::SyncService* sync_service);
   ~PasswordSessionDurationsMetricsRecorder() override;
 
   PasswordSessionDurationsMetricsRecorder(
@@ -47,7 +44,6 @@
  private:
   void CheckForUserStateChange();
 
-  const raw_ptr<PrefService> pref_service_;
   const raw_ptr<syncer::SyncService> sync_service_;
 
   base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver>
diff --git a/components/password_manager/core/browser/password_sync_util.cc b/components/password_manager/core/browser/password_sync_util.cc
index 5d8c072..c9c642a 100644
--- a/components/password_manager/core/browser/password_sync_util.cc
+++ b/components/password_manager/core/browser/password_sync_util.cc
@@ -100,13 +100,12 @@
 }
 
 std::optional<std::string> GetAccountForSaving(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service) {
   if (!sync_service) {
     return std::nullopt;
   }
   if (IsSyncFeatureEnabledIncludingPasswords(sync_service) ||
-      features_util::IsAccountStorageEnabled(pref_service, sync_service)) {
+      features_util::IsAccountStorageEnabled(sync_service)) {
     return sync_service->GetAccountInfo().email;
   }
   return std::nullopt;
diff --git a/components/password_manager/core/browser/password_sync_util.h b/components/password_manager/core/browser/password_sync_util.h
index d945a27..2a028b46f 100644
--- a/components/password_manager/core/browser/password_sync_util.h
+++ b/components/password_manager/core/browser/password_sync_util.h
@@ -82,7 +82,6 @@
 // are being saved only locally. In practice, this returns a non-empty
 // value if the user is syncing or signed in and opted in to account storage.
 std::optional<std::string> GetAccountForSaving(
-    const PrefService* pref_service,
     const syncer::SyncService* sync_service);
 
 // Reports whether and how passwords are currently synced. In particular, for a
diff --git a/components/password_manager/core/browser/sharing/password_receiver_service_impl.cc b/components/password_manager/core/browser/sharing/password_receiver_service_impl.cc
index 8b52f56..706fa3ab 100644
--- a/components/password_manager/core/browser/sharing/password_receiver_service_impl.cc
+++ b/components/password_manager/core/browser/sharing/password_receiver_service_impl.cc
@@ -17,7 +17,6 @@
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_store/password_store_interface.h"
 #include "components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_sync_bridge.h"
-#include "components/prefs/pref_service.h"
 #include "components/sync/model/data_type_controller_delegate.h"
 #include "components/sync/service/sync_service.h"
 
@@ -215,16 +214,12 @@
 }
 
 PasswordReceiverServiceImpl::PasswordReceiverServiceImpl(
-    const PrefService* pref_service,
     std::unique_ptr<IncomingPasswordSharingInvitationSyncBridge> sync_bridge,
     PasswordStoreInterface* profile_password_store,
     PasswordStoreInterface* account_password_store)
-    : pref_service_(pref_service),
-      sync_bridge_(std::move(sync_bridge)),
+    : sync_bridge_(std::move(sync_bridge)),
       profile_password_store_(profile_password_store),
       account_password_store_(account_password_store) {
-  CHECK(pref_service_);
-
   // |sync_bridge_| can be empty in tests.
   if (sync_bridge_) {
     sync_bridge_->SetPasswordReceiverService(this);
@@ -241,7 +236,7 @@
   // server. In case, `sync_service_` is null (e.g. due to a weird corner case
   // of destruction of sync service after delivering the invitation), both
   // checks below evaluate to false and hence the invitation will be ignored.
-  if (features_util::IsAccountStorageEnabled(pref_service_, sync_service_)) {
+  if (features_util::IsAccountStorageEnabled(sync_service_)) {
     password_store = account_password_store_;
   } else if (sync_service_ && sync_service_->IsSyncFeatureEnabled()) {
     password_store = profile_password_store_;
diff --git a/components/password_manager/core/browser/sharing/password_receiver_service_impl.h b/components/password_manager/core/browser/sharing/password_receiver_service_impl.h
index 363e378..a5b5b64 100644
--- a/components/password_manager/core/browser/sharing/password_receiver_service_impl.h
+++ b/components/password_manager/core/browser/sharing/password_receiver_service_impl.h
@@ -17,8 +17,6 @@
 #include "components/sync/protocol/password_sharing_invitation_specifics.pb.h"
 #include "components/sync/service/sync_service_observer.h"
 
-class PrefService;
-
 namespace password_manager {
 
 class PasswordStoreInterface;
@@ -70,7 +68,6 @@
   // `sync_bridge`, `profile_password_store` and `account_password_store` may be
   // nullptr in tests.
   explicit PasswordReceiverServiceImpl(
-      const PrefService* pref_service,
       std::unique_ptr<IncomingPasswordSharingInvitationSyncBridge> sync_bridge,
       PasswordStoreInterface* profile_password_store,
       PasswordStoreInterface* account_password_store);
@@ -92,8 +89,6 @@
  private:
   void RemoveTaskFromTasksList(ProcessIncomingSharingInvitationTask* task);
 
-  const raw_ptr<const PrefService> pref_service_;
-
   raw_ptr<syncer::SyncService> sync_service_ = nullptr;
 
   std::unique_ptr<IncomingPasswordSharingInvitationSyncBridge> sync_bridge_;
diff --git a/components/password_manager/core/browser/sharing/password_receiver_service_impl_unittest.cc b/components/password_manager/core/browser/sharing/password_receiver_service_impl_unittest.cc
index 3d32030..d28014f 100644
--- a/components/password_manager/core/browser/sharing/password_receiver_service_impl_unittest.cc
+++ b/components/password_manager/core/browser/sharing/password_receiver_service_impl_unittest.cc
@@ -22,8 +22,6 @@
 #include "components/password_manager/core/browser/password_store/test_password_store.h"
 #include "components/password_manager/core/browser/sharing/incoming_password_sharing_invitation_sync_bridge.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
 #include "components/sync/base/features.h"
 #include "components/sync/base/user_selectable_type.h"
 #include "components/sync/service/sync_service.h"
@@ -106,65 +104,28 @@
   return invitation;
 }
 
+scoped_refptr<TestPasswordStore> CreateStoreAndInit(
+    std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper) {
+  scoped_refptr<TestPasswordStore> store =
+      base::MakeRefCounted<TestPasswordStore>();
+  store->Init(/*prefs=*/nullptr, std::move(affiliated_match_helper));
+  return store;
+}
+
 }  // namespace
 
-// See ShouldCreateAccountStoreParam() for the meaning of the parameters.
-class PasswordReceiverServiceImplTest : public testing::TestWithParam<bool> {
+class PasswordReceiverServiceImplTest : public testing::Test {
  public:
-  void SetUp() override {
-#if BUILDFLAG(IS_ANDROID)
-    if (base::FeatureList::IsEnabled(features::kLoginDbDeprecationAndroid) &&
-        !ShouldCreateAccountStoreParam()) {
-      GTEST_SKIP() << "With kLoginDbDeprecationAndroid, the account store is "
-                      "always created";
-    }
-#endif  // BUILDFLAG(IS_ANDROID)
-
-    profile_password_store_ = base::MakeRefCounted<TestPasswordStore>();
-    affiliated_match_helper_profile_store_ =
-        new MockAffiliatedMatchHelper(&affiliation_service_);
-    profile_password_store_->Init(
-        /*prefs=*/nullptr,
-        base::WrapUnique(affiliated_match_helper_profile_store_.get()));
-
-#if BUILDFLAG(IS_ANDROID)
-    pref_service_.registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOff));
-#endif  // BUILDFLAG(IS_ANDROID)
-    if (ShouldCreateAccountStoreParam()) {
-#if BUILDFLAG(IS_ANDROID)
-      pref_service_.SetInteger(
-          prefs::kPasswordsUseUPMLocalAndSeparateStores,
-          static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-#endif
-      account_password_store_ = base::MakeRefCounted<TestPasswordStore>();
-      affiliated_match_helper_account_store_ =
-          new MockAffiliatedMatchHelper(&affiliation_service_);
-      account_password_store_->Init(
-          /*prefs=*/nullptr,
-          base::WrapUnique(affiliated_match_helper_account_store_.get()));
-    }
-
+  PasswordReceiverServiceImplTest() {
     sync_service_.SetSignedIn(signin::ConsentLevel::kSync);
-
-    password_receiver_service_ = std::make_unique<PasswordReceiverServiceImpl>(
-        &pref_service_,
-        /*sync_bridge=*/nullptr, profile_password_store_.get(),
-        account_password_store_.get());
     password_receiver_service_->OnSyncServiceInitialized(&sync_service_);
   }
 
-  void TearDown() override {
+  ~PasswordReceiverServiceImplTest() override {
     affiliated_match_helper_profile_store_ = nullptr;
     affiliated_match_helper_account_store_ = nullptr;
-    if (account_password_store_) {
-      account_password_store_->ShutdownOnUIThread();
-    }
-    if (profile_password_store_) {
-      profile_password_store_->ShutdownOnUIThread();
-    }
-    testing::Test::TearDown();
+    account_password_store_->ShutdownOnUIThread();
+    profile_password_store_->ShutdownOnUIThread();
   }
 
   void RunUntilIdle() { task_environment_.RunUntilIdle(); }
@@ -199,14 +160,12 @@
   }
 
   // The PasswordStore where sync-the-feature users should store shared
-  // passwords. This depends only on the platform and feature flags. It isn't
-  // affected by whether the user under test is currently syncing or not.
+  // passwords. This depends only on the platform. It isn't affected by whether
+  // the user under test is currently syncing or not.
   TestPasswordStore& expected_password_store_for_syncing() {
 #if BUILDFLAG(IS_ANDROID)
-    // Android is different from other platforms, syncing users use the
-    // account store whenever it's present.
-    return ShouldCreateAccountStoreParam() ? account_password_store()
-                                           : profile_password_store();
+    // Android differs from the rest, syncing users use the account store.
+    return account_password_store();
 #else
     return profile_password_store();
 #endif  // BUILDFLAG(IS_ANDROID)
@@ -214,9 +173,6 @@
 
   // The PasswordStore where syncing users should NOT store shared passwords.
   TestPasswordStore& unexpected_password_store_for_syncing() {
-    EXPECT_TRUE(ShouldCreateAccountStoreParam())
-        << "unexpected_password_store_for_syncing() must only be called if "
-           "there are 2 PasswordStores";
 #if BUILDFLAG(IS_ANDROID)
     return profile_password_store();
 #else
@@ -241,35 +197,32 @@
                : *affiliated_match_helper_profile_store_;
   }
 
-  TestingPrefServiceSimple& pref_service() { return pref_service_; }
   syncer::TestSyncService& sync_service() { return sync_service_; }
 
-  // Whether the test should instantiate the account-scoped PasswordStore.
-  bool ShouldCreateAccountStoreParam() { return GetParam(); }
-
  private:
   base::test::SingleThreadTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-
-  base::test::ScopedFeatureList feature_list_;
-  TestingPrefServiceSimple pref_service_;
-  syncer::TestSyncService sync_service_;
-  scoped_refptr<TestPasswordStore> profile_password_store_;
-  scoped_refptr<TestPasswordStore> account_password_store_;
-  std::unique_ptr<PasswordReceiverServiceImpl> password_receiver_service_;
   affiliations::FakeAffiliationService affiliation_service_;
   raw_ptr<MockAffiliatedMatchHelper> affiliated_match_helper_profile_store_ =
-      nullptr;
+      new MockAffiliatedMatchHelper(&affiliation_service_);
+  const scoped_refptr<TestPasswordStore> profile_password_store_ =
+      CreateStoreAndInit(
+          base::WrapUnique(affiliated_match_helper_profile_store_.get()));
   raw_ptr<MockAffiliatedMatchHelper> affiliated_match_helper_account_store_ =
-      nullptr;
+      new MockAffiliatedMatchHelper(&affiliation_service_);
+  const scoped_refptr<TestPasswordStore> account_password_store_ =
+      CreateStoreAndInit(
+          base::WrapUnique(affiliated_match_helper_account_store_.get()));
+  std::unique_ptr<PasswordReceiverServiceImpl> password_receiver_service_ =
+      std::make_unique<PasswordReceiverServiceImpl>(
+          /*sync_bridge=*/nullptr,
+          profile_password_store_.get(),
+          account_password_store_.get());
+  syncer::TestSyncService sync_service_;
 };
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldAcceptIncomingInvitationWhenStoreIsEmpty) {
-  if (!ShouldCreateAccountStoreParam()) {
-    return;
-  }
-
   base::HistogramTester histogram_tester;
   sync_pb::IncomingPasswordSharingInvitationSpecifics invitation =
       CreateIncomingSharingInvitation();
@@ -304,7 +257,7 @@
       1);
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldIgnoreIncomingInvitationWhenPasswordAlreadyExists) {
   base::HistogramTester histogram_tester;
   PasswordForm existing_password = CreatePasswordForm();
@@ -336,7 +289,7 @@
       1);
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldIgnoreIncomingInvitationWhenConflictingPasswordExists) {
   base::HistogramTester histogram_tester;
   PasswordForm password = CreatePasswordForm();
@@ -367,20 +320,15 @@
       1);
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldAcceptInvitationForNonSyncingUserWithAccountStorageEnabled) {
-  if (!ShouldCreateAccountStoreParam()) {
-    return;
-  }
-
   ASSERT_TRUE(profile_password_store().stored_passwords().empty());
   ASSERT_TRUE(account_password_store().stored_passwords().empty());
 
   // Set up an account store user (a non-syncing one, but that doesn't really
   // matter).
   sync_service().SetSignedIn(signin::ConsentLevel::kSignin);
-  ASSERT_TRUE(
-      features_util::IsAccountStorageEnabled(&pref_service(), &sync_service()));
+  ASSERT_TRUE(features_util::IsAccountStorageEnabled(&sync_service()));
 
   password_receiver_service()->ProcessIncomingSharingInvitation(
       CreateIncomingSharingInvitation());
@@ -391,13 +339,9 @@
   EXPECT_EQ(1U, account_password_store().stored_passwords().size());
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldNotAcceptInvitationForNonSyncingUserWithAccountStorageDisabled) {
   base::HistogramTester histogram_tester;
-  if (!ShouldCreateAccountStoreParam()) {
-    return;
-  }
-
   ASSERT_TRUE(profile_password_store().stored_passwords().empty());
   ASSERT_TRUE(account_password_store().stored_passwords().empty());
 
@@ -405,8 +349,7 @@
   sync_service().SetSignedIn(signin::ConsentLevel::kSignin);
   sync_service().GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, false);
-  ASSERT_FALSE(
-      features_util::IsAccountStorageEnabled(&pref_service(), &sync_service()));
+  ASSERT_FALSE(features_util::IsAccountStorageEnabled(&sync_service()));
 
   password_receiver_service()->ProcessIncomingSharingInvitation(
       CreateIncomingSharingInvitation());
@@ -423,7 +366,7 @@
       1);
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldRecordWhenSharedPasswordAlreadyExistsWithDifferentPassword) {
   base::HistogramTester histogram_tester;
   PasswordForm existing_password = CreatePasswordForm();
@@ -447,7 +390,7 @@
       1);
 }
 
-TEST_P(
+TEST_F(
     PasswordReceiverServiceImplTest,
     ShouldRecordWhenSharedPasswordAlreadyExistsAsSharedFromSameSenderWithSamePassword) {
   base::HistogramTester histogram_tester;
@@ -474,7 +417,7 @@
       1);
 }
 
-TEST_P(
+TEST_F(
     PasswordReceiverServiceImplTest,
     ShouldRecordWhenSharedPasswordAlreadyExistsAsSharedFromDifferentSenderWithSamePassword) {
   base::HistogramTester histogram_tester;
@@ -501,7 +444,7 @@
       1);
 }
 
-TEST_P(
+TEST_F(
     PasswordReceiverServiceImplTest,
     ShouldRecordWhenSharedPasswordAlreadyExistsAsSharedFromSameSenderWithDifferentPassword) {
   base::HistogramTester histogram_tester;
@@ -529,7 +472,7 @@
       1);
 }
 
-TEST_P(
+TEST_F(
     PasswordReceiverServiceImplTest,
     ShouldRecordWhenSharedPasswordAlreadyExistsAsSharedFromDifferentSenderWithDifferentPassword) {
   base::HistogramTester histogram_tester;
@@ -557,7 +500,7 @@
       1);
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldIgnorePasswordUpdatesFromSameSenderWhenAutoApproveDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
@@ -594,7 +537,7 @@
                               PasswordForm::Type::kReceivedViaSharing))));
 }
 
-TEST_P(PasswordReceiverServiceImplTest,
+TEST_F(PasswordReceiverServiceImplTest,
        ShouldAcceptPasswordUpdatesFromSameSenderWhenAutoApproveEnabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
@@ -631,7 +574,7 @@
                               PasswordForm::Type::kReceivedViaSharing))));
 }
 
-TEST_P(PasswordReceiverServiceImplTest, ShouldAddAllCredentialsInInvitation) {
+TEST_F(PasswordReceiverServiceImplTest, ShouldAddAllCredentialsInInvitation) {
   base::HistogramTester histogram_tester;
   sync_pb::IncomingPasswordSharingInvitationSpecifics invitation =
       CreateIncomingSharingInvitation();
@@ -677,7 +620,7 @@
       2);
 }
 
-TEST_P(PasswordReceiverServiceImplTest, ShouldIgnoreInvalidPasswordForm) {
+TEST_F(PasswordReceiverServiceImplTest, ShouldIgnoreInvalidPasswordForm) {
   base::HistogramTester histogram_tester;
   PasswordForm existing_password = CreatePasswordForm();
   existing_password.password_value.clear();
@@ -695,7 +638,7 @@
       1);
 }
 
-TEST_P(PasswordReceiverServiceImplTest, ShouldIgnoreGroupedCredentials) {
+TEST_F(PasswordReceiverServiceImplTest, ShouldIgnoreGroupedCredentials) {
   base::HistogramTester histogram_tester;
   PasswordForm existing_password = CreatePasswordForm();
   existing_password.scheme = PasswordForm::Scheme::kHtml;
@@ -728,15 +671,4 @@
       1);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ,
-    PasswordReceiverServiceImplTest,
-    ValuesIn({
-#if BUILDFLAG(IS_ANDROID)
-        // Android is the only platform where the account store might not be
-        // created, if kLoginDbDeprecationAndroid is disabled.
-        false,
-#endif
-        true}));
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/store_metrics_reporter.cc b/components/password_manager/core/browser/store_metrics_reporter.cc
index 8d080e8..8df0cc05 100644
--- a/components/password_manager/core/browser/store_metrics_reporter.cc
+++ b/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -753,7 +753,7 @@
       password_manager::sync_util::GetPasswordSyncState(sync_service));
 
   is_account_storage_enabled_ =
-      features_util::IsAccountStorageEnabled(prefs_, sync_service);
+      features_util::IsAccountStorageEnabled(sync_service);
 
   is_safe_browsing_enabled_ = safe_browsing::IsSafeBrowsingEnabled(*prefs_);
 
diff --git a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
index 7362b6e..be09feb 100644
--- a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
+++ b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -188,12 +188,6 @@
     prefs_.registry()->RegisterBooleanPref(
         prefs::kBiometricAuthenticationBeforeFilling, false);
 #endif
-#if BUILDFLAG(IS_ANDROID)
-    prefs_.registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(
-            password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
-#endif
   }
 
   void TearDown() override { OSCryptMocker::TearDown(); }
@@ -1437,13 +1431,6 @@
 // A test that covers multi-store metrics, which are recorded by the
 // StoreMetricsReporter directly.
 TEST_F(StoreMetricsReporterTest, MultiStoreMetrics) {
-#if BUILDFLAG(IS_ANDROID)
-  prefs_.SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(
-          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
-#endif  // BUILDFLAG(IS_ANDROID)
-
   auto profile_store =
       base::MakeRefCounted<TestPasswordStore>(IsAccountStore(false));
   auto account_store =
@@ -1510,9 +1497,8 @@
       test_sync_service()->GetUserSettings()->SetSelectedTypes(
           /*sync_everything=*/false, syncer::UserSelectableTypeSet());
     }
-    ASSERT_EQ(
-        features_util::IsAccountStorageEnabled(pref_service(), sync_service()),
-        account_storage_enabled);
+    ASSERT_EQ(features_util::IsAccountStorageEnabled(sync_service()),
+              account_storage_enabled);
 
     // In every pass in the loop, StoreMetricsReporter uses the same pref
     // service. Set the kLastTimePasswordStoreMetricsReported to make sure
diff --git a/components/password_manager/core/browser/sync/password_data_type_controller.cc b/components/password_manager/core/browser/sync/password_data_type_controller.cc
index 89bd783..8f02a6c 100644
--- a/components/password_manager/core/browser/sync/password_data_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_data_type_controller.cc
@@ -9,7 +9,6 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "build/build_config.h"
-#include "components/password_manager/core/browser/features/password_manager_features_util.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
@@ -48,12 +47,10 @@
   DCHECK(CalledOnValidThread());
   syncer::ConfigureContext overridden_context = configure_context;
 #if BUILDFLAG(IS_ANDROID)
-  if (features_util::CanCreateAccountStore(pref_service_)) {
-    // Make syncing users behave like signed-in users, storage-wise.
-    // TODO(crbug.com/40067058): Drop when kForceMigrateSyncingUserToSignedIn
-    // is launched on Android, since there won't be syncing users anymore.
-    overridden_context.sync_mode = syncer::SyncMode::kTransportOnly;
-  }
+  // Make syncing users behave like signed-in users, storage-wise.
+  // TODO(crbug.com/40067058): Drop when kForceMigrateSyncingUserToSignedIn
+  // is launched on Android, since there won't be syncing users anymore.
+  overridden_context.sync_mode = syncer::SyncMode::kTransportOnly;
 #endif
   sync_mode_ = overridden_context.sync_mode;
   DataTypeController::LoadModels(overridden_context, model_load_callback);
diff --git a/components/password_manager/core/browser/sync/password_data_type_controller_unittest.cc b/components/password_manager/core/browser/sync/password_data_type_controller_unittest.cc
index 844a3b77..53e251c 100644
--- a/components/password_manager/core/browser/sync/password_data_type_controller_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_data_type_controller_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "components/password_manager/core/browser/features/password_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
@@ -35,9 +34,6 @@
  public:
   PasswordDataTypeControllerTest() {
 #if BUILDFLAG(IS_ANDROID)
-    pref_service_.registry()->RegisterIntegerPref(
-        prefs::kPasswordsUseUPMLocalAndSeparateStores,
-        static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOff));
     pref_service_.registry()->RegisterBooleanPref(
         prefs::kAccountStorageNoticeShown, false);
 #endif
@@ -82,49 +78,7 @@
 };
 
 #if BUILDFLAG(IS_ANDROID)
-TEST_F(PasswordDataTypeControllerTest,
-       OverrideFullSyncModeIfUPMLocalOn_LoginDbDeprecationOff) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kLoginDbDeprecationAndroid);
-  pref_service()->SetInteger(
-      prefs::kPasswordsUseUPMLocalAndSeparateStores,
-      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
-  // `transport_only_delegate` should be used, despite syncer::SyncMode::kFull
-  // being passed below.
-  EXPECT_CALL(*full_sync_delegate(), OnSyncStarting).Times(0);
-  EXPECT_CALL(*transport_only_delegate(), OnSyncStarting);
-
-  syncer::ConfigureContext context;
-  context.authenticated_gaia_id = GaiaId("gaia");
-  context.cache_guid = "cache_guid";
-  context.sync_mode = syncer::SyncMode::kFull;
-  context.reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
-  context.configuration_start_time = base::Time::Now();
-  controller()->LoadModels(context, base::DoNothing());
-}
-
-TEST_F(PasswordDataTypeControllerTest,
-       DoNotOverrideFullSyncModeIfUPMLocalOff_LoginDbDeprecationOff) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(features::kLoginDbDeprecationAndroid);
-  // `full_sync_delegate` should be used for syncer::SyncMode::kFull, as
-  // expected.
-  EXPECT_CALL(*full_sync_delegate(), OnSyncStarting);
-  EXPECT_CALL(*transport_only_delegate(), OnSyncStarting).Times(0);
-
-  syncer::ConfigureContext context;
-  context.authenticated_gaia_id = GaiaId("gaia");
-  context.cache_guid = "cache_guid";
-  context.sync_mode = syncer::SyncMode::kFull;
-  context.reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
-  context.configuration_start_time = base::Time::Now();
-  controller()->LoadModels(context, base::DoNothing());
-}
-
-TEST_F(PasswordDataTypeControllerTest,
-       OverrideFullSyncMode_LoginDbDeprecationOn) {
-  base::test::ScopedFeatureList feature_list(
-      features::kLoginDbDeprecationAndroid);
+TEST_F(PasswordDataTypeControllerTest, OverrideFullSyncMode) {
   // `transport_only_delegate` should be used, despite syncer::SyncMode::kFull
   // being passed below.
   EXPECT_CALL(*full_sync_delegate(), OnSyncStarting).Times(0);
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h
index dda7ba7a..391b2789 100644
--- a/components/password_manager/core/common/password_manager_pref_names.h
+++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -69,20 +69,6 @@
 
 #if BUILDFLAG(IS_ANDROID)
 
-// The timestamp at which the UPM password access loss warning was last
-// shown to the user at the time of Chrome startup in microseconds since Windows
-// epoch. This is needed to ensure that the UI is prompted only once per given
-// time interval (currently seven days).
-inline constexpr char kPasswordAccessLossWarningShownAtStartupTimestamp[] =
-    "password_access_loss_warning_shown_at_startup_timestamp";
-
-// The timestamp at which the UPM password access loss warning was last
-// shown to the user in microseconds since Windows epoch. This is needed to
-// ensure that the UI is prompted only once per given time interval (currently
-// one day).
-inline constexpr char kPasswordAccessLossWarningShownTimestamp[] =
-    "password_access_loss_warning_shown_timestamp";
-
 // Boolean pref indicating if the one-time notice for account storage was shown.
 // The notice informs passwords will start being saved to the signed-in account.
 inline constexpr char kAccountStorageNoticeShown[] =
@@ -111,21 +97,10 @@
 inline constexpr char kOfferToSavePasswordsEnabledGMS[] =
     "profile.save_passwords_enabed_gms";
 
-// Boolean value indicating whether the regular prefs that apply to the local
-// password store were migrated to UPM settings. It will be set to true
-// automatically if there is nothing to migrate.
-inline constexpr char kSettingsMigratedToUPMLocal[] =
-    "profile.settings_migrated_to_upm_local";
-
 // Integer value which indicates the version used to migrate passwords from
 // built in storage to Google Mobile Services.
 inline constexpr char kCurrentMigrationVersionToGoogleMobileServices[] =
     "current_migration_version_to_google_mobile_services";
-
-// Timestamps of when credentials from the GMS Core to the built in storage were
-// last time migrated, in milliseconds since UNIX epoch.
-inline constexpr char kTimeOfLastMigrationAttempt[] =
-    "time_of_last_migration_attempt";
 #endif
 
 // The total amount of passwords available in Password Manager account store.
diff --git a/components/payments/content/android/payment_request_update_event_listener.cc b/components/payments/content/android/payment_request_update_event_listener.cc
index 776a5140..e6a2f0f 100644
--- a/components/payments/content/android/payment_request_update_event_listener.cc
+++ b/components/payments/content/android/payment_request_update_event_listener.cc
@@ -47,7 +47,7 @@
   std::vector<uint8_t> byte_vector =
       mojom::PaymentAddress::Serialize(&shipping_address);
   JNIEnv* env = base::android::AttachCurrentThread();
-  base::android::ScopedJavaLocalRef<jobject> obj(
+  auto obj = base::android::ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size()));
   base::android::CheckException(env);
   return Java_PaymentRequestUpdateEventListener_changeShippingAddress(
diff --git a/components/policy/core/common/android/policy_converter_unittest.cc b/components/policy/core/common/android/policy_converter_unittest.cc
index e60d003..9e3f3cf4 100644
--- a/components/policy/core/common/android/policy_converter_unittest.cc
+++ b/components/policy/core/common/android/policy_converter_unittest.cc
@@ -84,7 +84,7 @@
           base::android::ConvertUTF8ToJavaString(env, values[i]).obj());
     }
 
-    return ScopedJavaLocalRef<jobjectArray>(env, java_array);
+    return ScopedJavaLocalRef<jobjectArray>::Adopt(env, java_array);
   }
 
   Schema schema_;
diff --git a/components/policy/resources/templates/policy_definitions/CloudReporting/CloudProfileReportingEnabled.yaml b/components/policy/resources/templates/policy_definitions/CloudReporting/CloudProfileReportingEnabled.yaml
index a48a063..206cb45 100644
--- a/components/policy/resources/templates/policy_definitions/CloudReporting/CloudProfileReportingEnabled.yaml
+++ b/components/policy/resources/templates/policy_definitions/CloudReporting/CloudProfileReportingEnabled.yaml
@@ -21,6 +21,7 @@
 future_on:
 - chrome_os
 - fuchsia
+- ios
 items:
 - caption: Enable managed profile cloud reporting
   value: true
diff --git a/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessAllowedForUrls.yaml b/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessAllowedForUrls.yaml
index f81d43d..ecdcccc6 100644
--- a/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessAllowedForUrls.yaml
+++ b/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessAllowedForUrls.yaml
@@ -14,7 +14,7 @@
 
   For detailed information on valid URL patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.
 
-  See https://github.com/explainers-by-googlers/local-network-access for <ph
+  See https://wicg.github.io/local-network-access/ for <ph
   name="LOCAL_NETWORK_ACCESS">Local Network Access</ph> restrictions.
 
 example_value:
diff --git a/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessBlockedForUrls.yaml b/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessBlockedForUrls.yaml
index 3587720..057e8904 100644
--- a/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessBlockedForUrls.yaml
+++ b/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessBlockedForUrls.yaml
@@ -16,7 +16,7 @@
 
   For detailed information on valid URL patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.
 
-  See https://github.com/explainers-by-googlers/local-network-access for <ph
+  See https://wicg.github.io/local-network-access/ for <ph
   name="LOCAL_NETWORK_ACCESS">Local Network Access</ph> restrictions.
 
 example_value:
diff --git a/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessRestrictionsEnabled.yaml b/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessRestrictionsEnabled.yaml
index 18a5b61..2bb4de61 100644
--- a/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessRestrictionsEnabled.yaml
+++ b/components/policy/resources/templates/policy_definitions/LocalNetworkAccessSettings/LocalNetworkAccessRestrictionsEnabled.yaml
@@ -16,7 +16,7 @@
   name="LOCAL_NETWORK_ACCESS">Local Network Access</ph> requests will use the
   default handling of these requests.
 
-  See https://github.com/explainers-by-googlers/local-network-access for <ph
+  See https://wicg.github.io/local-network-access/ for <ph
   name="LOCAL_NETWORK_ACCESS">Local Network Access</ph> restrictions.
 default: false
 
diff --git a/components/policy/resources/templates/policy_definitions/ParentalSupervision/EduCoexistenceToSVersion.yaml b/components/policy/resources/templates/policy_definitions/ParentalSupervision/EduCoexistenceToSVersion.yaml
index 77ad257..872207d 100644
--- a/components/policy/resources/templates/policy_definitions/ParentalSupervision/EduCoexistenceToSVersion.yaml
+++ b/components/policy/resources/templates/policy_definitions/ParentalSupervision/EduCoexistenceToSVersion.yaml
@@ -12,9 +12,8 @@
   dynamic_refresh: true
   per_profile: false
 owners:
-- agawronska@chromium.org
-- danan@chromium.org
-- yilkal@chromium.org
+- zhangwenyu@googe.com
+- longbowei@google.com
 - cros-families-eng@google.com
 schema:
   description: The valid version of Terms of Service derived from Google3 cl that
diff --git a/components/policy/resources/templates/policy_definitions/ParentalSupervision/ParentAccessCodeConfig.yaml b/components/policy/resources/templates/policy_definitions/ParentalSupervision/ParentAccessCodeConfig.yaml
index 2e7edbf0..1eadbe2 100644
--- a/components/policy/resources/templates/policy_definitions/ParentalSupervision/ParentAccessCodeConfig.yaml
+++ b/components/policy/resources/templates/policy_definitions/ParentalSupervision/ParentAccessCodeConfig.yaml
@@ -30,7 +30,8 @@
   per_profile: false
 owners:
 - file://chrome/browser/ash/child_accounts/OWNERS
-- agawronska@chromium.org
+- zhangwenyu@googe.com
+- longbowei@google.com
 schema:
   properties:
     current_config:
diff --git a/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimits.yaml b/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimits.yaml
index d138a22..27466c5 100644
--- a/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimits.yaml
+++ b/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimits.yaml
@@ -39,7 +39,8 @@
   dynamic_refresh: true
   per_profile: false
 owners:
-- agawronska@chromium.org
+- zhangwenyu@googe.com
+- longbowei@google.com
 - cros-families-eng@google.com
 schema:
   properties:
diff --git a/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimitsAllowlist.yaml b/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimitsAllowlist.yaml
index 9f5c672..c0f1689 100644
--- a/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimitsAllowlist.yaml
+++ b/components/policy/resources/templates/policy_definitions/ParentalSupervision/PerAppTimeLimitsAllowlist.yaml
@@ -25,7 +25,8 @@
   dynamic_refresh: true
   per_profile: false
 owners:
-- yilkal@chromium.org
+- zhangwenyu@google.com
+- longbowei@google.com
 - cros-families-eng@google.com
 schema:
   properties:
diff --git a/components/policy/resources/templates/policy_definitions/Projector/ProjectorDogfoodForFamilyLinkEnabled.yaml b/components/policy/resources/templates/policy_definitions/Projector/ProjectorDogfoodForFamilyLinkEnabled.yaml
index 7f950614..0dff8dc 100644
--- a/components/policy/resources/templates/policy_definitions/Projector/ProjectorDogfoodForFamilyLinkEnabled.yaml
+++ b/components/policy/resources/templates/policy_definitions/Projector/ProjectorDogfoodForFamilyLinkEnabled.yaml
@@ -18,7 +18,8 @@
 - caption: Disable Screencast dogfood for Family Link users
   value: false
 owners:
-- agawronska@google.com
+- zhangwenyu@google.com
+- longbowei@google.com
 - llin@google.com
 - cros-projector@google.com
 schema:
diff --git a/components/prefs/BUILD.gn b/components/prefs/BUILD.gn
index 32ef37b..9415eaf 100644
--- a/components/prefs/BUILD.gn
+++ b/components/prefs/BUILD.gn
@@ -25,7 +25,6 @@
     "pref_notifier.h",
     "pref_notifier_impl.cc",
     "pref_notifier_impl.h",
-    "pref_observer.h",
     "pref_registry.cc",
     "pref_registry.h",
     "pref_registry_simple.cc",
diff --git a/components/prefs/pref_change_registrar.cc b/components/prefs/pref_change_registrar.cc
index bd5f35c..cb689a01 100644
--- a/components/prefs/pref_change_registrar.cc
+++ b/components/prefs/pref_change_registrar.cc
@@ -6,24 +6,25 @@
 
 #include <ostream>
 
+#include "base/callback_list.h"
 #include "base/check.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/notreached.h"
 #include "components/prefs/pref_service.h"
 
+namespace {
+
+// Returns a copy of `view`.
+std::string CopyStringView(std::string_view view) {
+  return std::string(view);
+}
+
+}  // namespace
+
 PrefChangeRegistrar::PrefChangeRegistrar() : service_(nullptr) {}
 
-PrefChangeRegistrar::~PrefChangeRegistrar() {
-  // If you see an invalid memory access in this destructor, this
-  // PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that
-  // has been destroyed. This should not happen any more but be warned.
-  // Feel free to contact battre@chromium.org in case this happens.
-  //
-  // This can also happen for non-OTR profiles, when the
-  // DestroyProfileOnBrowserClose flag is enabled. In that case, contact
-  // nicolaso@chromium.org.
-  RemoveAll();
-}
+PrefChangeRegistrar::~PrefChangeRegistrar() = default;
 
 void PrefChangeRegistrar::Init(PrefService* service) {
   DCHECK(IsEmpty() || service_ == service);
@@ -36,62 +37,43 @@
 }
 
 void PrefChangeRegistrar::Add(std::string_view path,
-                              const base::RepeatingClosure& obs) {
-  Add(path,
-      base::BindRepeating(&PrefChangeRegistrar::InvokeUnnamedCallback, obs));
+                              base::RepeatingClosure obs) {
+  Add(path, base::IgnoreArgs<std::string_view>(std::move(obs)));
+}
+
+void PrefChangeRegistrar::Add(std::string_view path, NamedChangeCallback obs) {
+  Add(path, base::BindRepeating(&CopyStringView).Then(std::move(obs)));
 }
 
 void PrefChangeRegistrar::Add(std::string_view path,
-                              const NamedChangeCallback& obs) {
-  if (!service_) {
-    NOTREACHED();
-  }
+                              NamedChangeAsViewCallback obs) {
+  CHECK(service_);
   DCHECK(!IsObserved(path)) << "Already had pref, \"" << path
                             << "\", registered.";
 
-  service_->AddPrefObserver(path, this);
-  observers_.insert_or_assign(std::string(path), obs);
+  subscriptions_.insert(std::make_pair(
+      path, service_->AddPrefChangedCallback(
+                path, base::IgnoreArgs<PrefService*>(std::move(obs)))));
 }
 
 void PrefChangeRegistrar::Remove(std::string_view path) {
   DCHECK(IsObserved(path));
 
   // Use std::map::erase directly once C++23 is supported.
-  auto it = observers_.find(path);
-  observers_.erase(it);
-  service_->RemovePrefObserver(path, this);
+  auto it = subscriptions_.find(path);
+  subscriptions_.erase(it);
 }
 
 void PrefChangeRegistrar::RemoveAll() {
-  for (ObserverMap::const_iterator it = observers_.begin();
-       it != observers_.end(); ++it) {
-    service_->RemovePrefObserver(it->first, this);
-  }
-
-  observers_.clear();
+  subscriptions_.clear();
 }
 
 bool PrefChangeRegistrar::IsEmpty() const {
-  return observers_.empty();
+  return subscriptions_.empty();
 }
 
 bool PrefChangeRegistrar::IsObserved(std::string_view pref) {
-  return observers_.find(pref) != observers_.end();
-}
-
-void PrefChangeRegistrar::OnPreferenceChanged(PrefService* service,
-                                              std::string_view pref) {
-  if (auto it = observers_.find(pref); it != observers_.end()) {
-    // TODO: crbug.com/349741884 - Consider changing the callback to accept a
-    // string_view.
-    it->second.Run(std::string(pref));
-  }
-}
-
-void PrefChangeRegistrar::InvokeUnnamedCallback(
-    const base::RepeatingClosure& callback,
-    const std::string& pref_name) {
-  callback.Run();
+  return subscriptions_.find(pref) != subscriptions_.end();
 }
 
 PrefService* PrefChangeRegistrar::prefs() {
diff --git a/components/prefs/pref_change_registrar.h b/components/prefs/pref_change_registrar.h
index edb0fdf3..fc6aa77 100644
--- a/components/prefs/pref_change_registrar.h
+++ b/components/prefs/pref_change_registrar.h
@@ -12,19 +12,24 @@
 
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
-#include "components/prefs/pref_observer.h"
 #include "components/prefs/prefs_export.h"
+#include "components/prefs/transparent_unordered_string_map.h"
 
 class PrefService;
+namespace base {
+class CallbackListSubscription;
+}
 
 // Automatically manages the registration of one or more pref change observers
 // with a PrefStore. When the Registrar is destroyed, all registered observers
 // are automatically unregistered with the PrefStore.
-class COMPONENTS_PREFS_EXPORT PrefChangeRegistrar final : public PrefObserver {
+class COMPONENTS_PREFS_EXPORT PrefChangeRegistrar {
  public:
   // You can register this type of callback if you need to know the
   // path of the preference that is changing.
   using NamedChangeCallback = base::RepeatingCallback<void(const std::string&)>;
+  using NamedChangeAsViewCallback =
+      base::RepeatingCallback<void(std::string_view)>;
 
   PrefChangeRegistrar();
 
@@ -49,8 +54,9 @@
   // the preference that is changing as its parameter.
   //
   // Only one observer may be registered per path.
-  void Add(std::string_view path, const base::RepeatingClosure& obs);
-  void Add(std::string_view path, const NamedChangeCallback& obs);
+  void Add(std::string_view path, base::RepeatingClosure obs);
+  void Add(std::string_view path, NamedChangeCallback obs);
+  void Add(std::string_view path, NamedChangeAsViewCallback obs);
 
   // Removes the pref observer registered for |path|.
   void Remove(std::string_view path);
@@ -69,16 +75,10 @@
   const PrefService* prefs() const;
 
  private:
-  // PrefObserver:
-  void OnPreferenceChanged(PrefService* service,
-                           std::string_view pref_name) override;
+  using SubscriptionMap =
+      TransparentUnorderedStringMap<base::CallbackListSubscription>;
 
-  static void InvokeUnnamedCallback(const base::RepeatingClosure& callback,
-                                    const std::string& pref_name);
-
-  using ObserverMap = std::map<std::string, NamedChangeCallback, std::less<>>;
-
-  ObserverMap observers_;
+  SubscriptionMap subscriptions_;
   raw_ptr<PrefService, AcrossTasksDanglingUntriaged> service_;
 };
 
diff --git a/components/prefs/pref_change_registrar_unittest.cc b/components/prefs/pref_change_registrar_unittest.cc
index d6de51b..1b2365d9 100644
--- a/components/prefs/pref_change_registrar_unittest.cc
+++ b/components/prefs/pref_change_registrar_unittest.cc
@@ -9,7 +9,6 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "components/prefs/pref_observer.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -24,22 +23,6 @@
 const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage";
 const char kApplicationLocale[] = "intl.app_locale";
 
-// A mock provider that allows us to capture pref observer changes.
-class MockPrefService : public TestingPrefServiceSimple {
- public:
-  MockPrefService() = default;
-  ~MockPrefService() override = default;
-
-  MOCK_METHOD(void,
-              AddPrefObserver,
-              (std::string_view, PrefObserver*),
-              (override));
-  MOCK_METHOD(void,
-              RemovePrefObserver,
-              (std::string_view, PrefObserver*),
-              (override));
-};
-
 // Due to overloads, base::DoNothing() cannot be passed directly to
 // PrefChangeRegistrar::Add() as it is convertible to all callbacks.
 base::RepeatingClosure DoNothingClosure() {
@@ -56,14 +39,14 @@
  protected:
   void SetUp() override;
 
-  MockPrefService* service() const { return service_.get(); }
+  TestingPrefServiceSimple* service() const { return service_.get(); }
 
  private:
-  std::unique_ptr<MockPrefService> service_;
+  std::unique_ptr<TestingPrefServiceSimple> service_;
 };
 
 void PrefChangeRegistrarTest::SetUp() {
-  service_ = std::make_unique<MockPrefService>();
+  service_ = std::make_unique<TestingPrefServiceSimple>();
 }
 
 TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
@@ -71,23 +54,14 @@
   registrar.Init(service());
 
   // Test adding.
-  EXPECT_CALL(*service(), AddPrefObserver("test.pref.1", &registrar));
-  EXPECT_CALL(*service(), AddPrefObserver("test.pref.2", &registrar));
   registrar.Add("test.pref.1", DoNothingClosure());
   registrar.Add("test.pref.2", DoNothingClosure());
   EXPECT_FALSE(registrar.IsEmpty());
 
   // Test removing.
-  Mock::VerifyAndClearExpectations(service());
-  EXPECT_CALL(*service(), RemovePrefObserver("test.pref.1", &registrar));
-  EXPECT_CALL(*service(), RemovePrefObserver("test.pref.2", &registrar));
   registrar.Remove("test.pref.1");
   registrar.Remove("test.pref.2");
   EXPECT_TRUE(registrar.IsEmpty());
-
-  // Explicitly check the expectations now to make sure that the Removes
-  // worked (rather than the registrar destructor doing the work).
-  Mock::VerifyAndClearExpectations(service());
 }
 
 TEST_F(PrefChangeRegistrarTest, AutoRemove) {
@@ -95,33 +69,19 @@
   registrar.Init(service());
 
   // Setup of auto-remove.
-  EXPECT_CALL(*service(), AddPrefObserver("test.pref.1", &registrar));
   registrar.Add("test.pref.1", DoNothingClosure());
-  Mock::VerifyAndClearExpectations(service());
   EXPECT_FALSE(registrar.IsEmpty());
-
-  // Test auto-removing.
-  EXPECT_CALL(*service(), RemovePrefObserver("test.pref.1", &registrar));
 }
 
 TEST_F(PrefChangeRegistrarTest, RemoveAll) {
   PrefChangeRegistrar registrar;
   registrar.Init(service());
 
-  EXPECT_CALL(*service(), AddPrefObserver("test.pref.1", &registrar));
-  EXPECT_CALL(*service(), AddPrefObserver("test.pref.2", &registrar));
   registrar.Add("test.pref.1", DoNothingClosure());
   registrar.Add("test.pref.2", DoNothingClosure());
-  Mock::VerifyAndClearExpectations(service());
 
-  EXPECT_CALL(*service(), RemovePrefObserver("test.pref.1", &registrar));
-  EXPECT_CALL(*service(), RemovePrefObserver("test.pref.2", &registrar));
   registrar.RemoveAll();
   EXPECT_TRUE(registrar.IsEmpty());
-
-  // Explicitly check the expectations now to make sure that the RemoveAll
-  // worked (rather than the registrar destructor doing the work).
-  Mock::VerifyAndClearExpectations(service());
 }
 
 class ObserveSetOfPreferencesTest : public testing::Test {
diff --git a/components/prefs/pref_member.cc b/components/prefs/pref_member.cc
index d054787f..2716f8958 100644
--- a/components/prefs/pref_member.cc
+++ b/components/prefs/pref_member.cc
@@ -40,13 +40,17 @@
   DCHECK(prefs_->FindPreference(pref_name_)) << pref_name << " not registered.";
 
   // Add ourselves as a pref observer so we can keep our local value in sync.
-  prefs_->AddPrefObserver(pref_name, this);
+  // Using base::Unretained(this) is safe since the callback won't be called
+  // after the returned subscription has been destroyed, and it is destroyed
+  // in PrefMemberBase's destructor.
+  subscription_ = prefs_->AddPrefChangedCallback(
+      pref_name,
+      base::IgnoreArgs<PrefService*>(base::BindRepeating(
+          &PrefMemberBase::OnPreferenceChanged, base::Unretained(this))));
 }
 
 void PrefMemberBase::Destroy() {
-  if (prefs_ && !pref_name_.empty()) {
-    prefs_->RemovePrefObserver(pref_name_, this);
-  }
+  subscription_ = base::CallbackListSubscription();
   prefs_ = nullptr;
 }
 
@@ -59,8 +63,7 @@
   internal()->MoveToSequence(std::move(task_runner));
 }
 
-void PrefMemberBase::OnPreferenceChanged(PrefService* service,
-                                         std::string_view pref_name) {
+void PrefMemberBase::OnPreferenceChanged(std::string_view pref_name) {
   VerifyValuePrefName();
   UpdateValueFromPref((!setting_value_ && !observer_.is_null())
                           ? base::BindOnce(observer_, std::string(pref_name))
diff --git a/components/prefs/pref_member.h b/components/prefs/pref_member.h
index d1f8a142..f3287aa 100644
--- a/components/prefs/pref_member.h
+++ b/components/prefs/pref_member.h
@@ -27,6 +27,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback_list.h"
 #include "base/check.h"
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
@@ -35,14 +36,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/values.h"
-#include "components/prefs/pref_observer.h"
 #include "components/prefs/prefs_export.h"
 
 class PrefService;
 
 namespace subtle {
 
-class COMPONENTS_PREFS_EXPORT PrefMemberBase : public PrefObserver {
+class COMPONENTS_PREFS_EXPORT PrefMemberBase {
  public:
   // Type of callback you can register if you need to know the name of
   // the pref that is changing.
@@ -111,9 +111,8 @@
 
   void MoveToSequence(scoped_refptr<base::SequencedTaskRunner> task_runner);
 
-  // PrefObserver:
-  void OnPreferenceChanged(PrefService* service,
-                           std::string_view pref_name) override;
+  // Invoked when a preference changes.
+  void OnPreferenceChanged(std::string_view pref_name);
 
   void VerifyValuePrefName() const {
     DCHECK(!pref_name_.empty());
@@ -141,6 +140,7 @@
   std::string pref_name_;
   NamedChangeCallback observer_;
   raw_ptr<PrefService> prefs_;
+  base::CallbackListSubscription subscription_;
 
  protected:
   bool setting_value_;
diff --git a/components/prefs/pref_notifier_impl.cc b/components/prefs/pref_notifier_impl.cc
index 76b3001b..13aa521e 100644
--- a/components/prefs/pref_notifier_impl.cc
+++ b/components/prefs/pref_notifier_impl.cc
@@ -4,8 +4,10 @@
 
 #include "components/prefs/pref_notifier_impl.h"
 
+#include "base/check.h"
 #include "base/debug/alias.h"
 #include "base/debug/dump_without_crashing.h"
+#include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/observer_list.h"
@@ -22,8 +24,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Verify that there are no pref observers when we shut down.
-  for (const auto& observer_list : pref_observers_) {
-    if (observer_list.second.begin() != observer_list.second.end()) {
+  for (const auto& observer_list : pref_changed_callbacks_) {
+    if (!observer_list.second.empty()) {
       // Generally, there should not be any subscribers left when the profile
       // is destroyed because a) those may indicate that the subscriber class
       // maintains an active pointer to the profile that might be used for
@@ -59,48 +61,50 @@
   if (!init_observers_.empty())
     LOG(WARNING) << "Init observer found at shutdown.";
 
-  pref_observers_.clear();
+  pref_changed_callbacks_.clear();
   init_observers_.clear();
 }
 
-void PrefNotifierImpl::AddPrefObserver(std::string_view path,
-                                       PrefObserver* obs) {
+base::CallbackListSubscription PrefNotifierImpl::AddPrefChangedCallback(
+    std::string_view path,
+    PrefChangedCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto iterator = pref_changed_callbacks_.find(path);
+  if (iterator == pref_changed_callbacks_.end()) {
+    bool inserted = false;
+    std::tie(iterator, inserted) = pref_changed_callbacks_.emplace(
+        std::piecewise_construct, std::forward_as_tuple(path),
+        std::forward_as_tuple());
+    DCHECK(inserted);
 
-  // Add the pref observer. ObserverList hits a DCHECK if it already is
-  // in the list.
-  pref_observers_[std::string(path)].AddObserver(obs);
-}
-
-void PrefNotifierImpl::RemovePrefObserver(std::string_view path,
-                                          PrefObserver* obs) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  auto observer_iterator = pref_observers_.find(path);
-  if (observer_iterator == pref_observers_.end()) {
-    return;
+    // Set a removal callback in order to remove the mapping when
+    // the last registered observer for `path` is removed. This
+    // avoid unbounded growth of the map (it will be limited to
+    // the maximum size of different preferences observer at the
+    // same time).
+    iterator->second.set_removal_callback(
+        base::BindRepeating(&PrefNotifierImpl::OnCallbacksRemoved,
+                            base::Unretained(this), std::string(path)));
   }
 
-  PrefObserverList& observer_list = observer_iterator->second;
-  observer_list.RemoveObserver(obs);
+  DCHECK(iterator != pref_changed_callbacks_.end());
+  return iterator->second.Add(std::move(callback));
 }
 
-void PrefNotifierImpl::AddPrefObserverAllPrefs(PrefObserver* observer) {
+base::CallbackListSubscription PrefNotifierImpl::AddAllPrefsChangedCallback(
+    PrefChangedCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  all_prefs_pref_observers_.AddObserver(observer);
-}
-
-void PrefNotifierImpl::RemovePrefObserverAllPrefs(PrefObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  all_prefs_pref_observers_.RemoveObserver(observer);
+  return all_prefs_changed_callbacks_.Add(std::move(callback));
 }
 
 void PrefNotifierImpl::AddInitObserver(base::OnceCallback<void(bool)> obs) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   init_observers_.push_back(std::move(obs));
 }
 
 void PrefNotifierImpl::OnPreferenceChanged(std::string_view path) {
-  FireObservers(path);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  NotifyCallbacks(path);
 }
 
 void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) {
@@ -116,7 +120,7 @@
     std::move(observer).Run(succeeded);
 }
 
-void PrefNotifierImpl::FireObservers(std::string_view path) {
+void PrefNotifierImpl::NotifyCallbacks(std::string_view path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Only send notifications for registered preferences.
@@ -124,16 +128,11 @@
     return;
 
   // Fire observers for any preference change.
-  for (PrefObserver& observer : all_prefs_pref_observers_) {
-    observer.OnPreferenceChanged(pref_service_, path);
-  }
+  all_prefs_changed_callbacks_.Notify(pref_service_, path);
 
-  auto observer_iterator = pref_observers_.find(path);
-  if (observer_iterator == pref_observers_.end())
-    return;
-
-  for (PrefObserver& observer : observer_iterator->second) {
-    observer.OnPreferenceChanged(pref_service_, path);
+  auto iterator = pref_changed_callbacks_.find(path);
+  if (iterator != pref_changed_callbacks_.end()) {
+    iterator->second.Notify(pref_service_, path);
   }
 }
 
@@ -141,3 +140,12 @@
   DCHECK(pref_service_ == nullptr);
   pref_service_ = pref_service;
 }
+
+void PrefNotifierImpl::OnCallbacksRemoved(const std::string& path) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto iterator = pref_changed_callbacks_.find(path);
+  DCHECK(iterator != pref_changed_callbacks_.end());
+  if (iterator->second.empty()) {
+    pref_changed_callbacks_.erase(iterator);
+  }
+}
diff --git a/components/prefs/pref_notifier_impl.h b/components/prefs/pref_notifier_impl.h
index 2025e2b8..fe0a4029 100644
--- a/components/prefs/pref_notifier_impl.h
+++ b/components/prefs/pref_notifier_impl.h
@@ -11,21 +11,27 @@
 #include <string_view>
 #include <unordered_map>
 
+#include "base/callback_list.h"
 #include "base/compiler_specific.h"
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/observer_list.h"
 #include "base/sequence_checker.h"
 #include "components/prefs/pref_notifier.h"
-#include "components/prefs/pref_observer.h"
 #include "components/prefs/prefs_export.h"
 #include "components/prefs/transparent_unordered_string_map.h"
 
 class PrefService;
+namespace base {
+class CallbackListSubscription;
+}
 
 // The PrefNotifier implementation used by the PrefService.
 class COMPONENTS_PREFS_EXPORT PrefNotifierImpl : public PrefNotifier {
  public:
+  using PrefChangedCallback =
+      base::RepeatingCallback<void(PrefService*, std::string_view)>;
+
   PrefNotifierImpl();
   explicit PrefNotifierImpl(PrefService* pref_service);
 
@@ -34,17 +40,19 @@
 
   ~PrefNotifierImpl() override;
 
-  // If the pref at the given path changes, we call the observer's
-  // OnPreferenceChanged method.
-  void AddPrefObserver(std::string_view path, PrefObserver* observer);
-  void RemovePrefObserver(std::string_view path, PrefObserver* observer);
+  // Registers the callback to be invoked if the pref at the given path
+  // changes. The callback is automatically unregistered if the returned
+  // CallbackListSubscription is destroyed.
+  base::CallbackListSubscription AddPrefChangedCallback(
+      std::string_view path,
+      PrefChangedCallback callback);
 
-  // These observers are called for any pref changes.
+  // These callbacks are called for any pref changes.
   //
   // AVOID ADDING THESE. See the long comment in the identically-named
   // functions on PrefService for background.
-  void AddPrefObserverAllPrefs(PrefObserver* observer);
-  void RemovePrefObserverAllPrefs(PrefObserver* observer);
+  base::CallbackListSubscription AddAllPrefsChangedCallback(
+      PrefChangedCallback callback);
 
   // We run the callback once, when initialization completes. The bool
   // parameter will be set to true for successful initialization,
@@ -60,28 +68,30 @@
   // PrefNotifier overrides.
   void OnInitializationCompleted(bool succeeded) override;
 
-  // A map from pref names to a list of observers. Observers get fired in the
-  // order they are added. These should only be accessed externally for unit
-  // testing.
-  using PrefObserverList = base::ObserverList<PrefObserver>::Unchecked;
-  using PrefObserverMap = TransparentUnorderedStringMap<PrefObserverList>;
+ private:
+  // A map from pref names to the list of registered callbacks. Callbacks get
+  // fired in the order they are added.
+  using PrefChangedCallbackList =
+      base::RepeatingCallbackList<void(PrefService*, std::string_view)>;
+  using PrefChangedCallbackMap =
+      TransparentUnorderedStringMap<PrefChangedCallbackList>;
   using PrefInitObserverList = std::list<base::OnceCallback<void(bool)>>;
 
-  const PrefObserverMap* pref_observers() const { return &pref_observers_; }
+  // For the given pref_name, notify any callbacks of the pref. Virtual so it
+  // can be mocked for unit testing.
+  virtual void NotifyCallbacks(std::string_view path);
 
- private:
-  // For the given pref_name, fire any observer of the pref. Virtual so it can
-  // be mocked for unit testing.
-  virtual void FireObservers(std::string_view path);
+  // Invoked when callbacks are removed for `path`.
+  void OnCallbacksRemoved(const std::string& path);
 
   // Weak reference; the notifier is owned by the PrefService.
   raw_ptr<PrefService> pref_service_;
 
-  PrefObserverMap pref_observers_;
+  PrefChangedCallbackMap pref_changed_callbacks_;
   PrefInitObserverList init_observers_;
 
   // Observers for changes to any preference.
-  PrefObserverList all_prefs_pref_observers_;
+  PrefChangedCallbackList all_prefs_changed_callbacks_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 };
diff --git a/components/prefs/pref_notifier_impl_unittest.cc b/components/prefs/pref_notifier_impl_unittest.cc
index 5506288e..0f0e4dd 100644
--- a/components/prefs/pref_notifier_impl_unittest.cc
+++ b/components/prefs/pref_notifier_impl_unittest.cc
@@ -9,8 +9,8 @@
 #include "base/dcheck_is_on.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
 #include "components/prefs/mock_pref_change_callback.h"
-#include "components/prefs/pref_observer.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/pref_value_store.h"
@@ -53,33 +53,16 @@
       : PrefNotifierImpl(pref_service) {}
   ~MockPrefNotifier() override = default;
 
-  MOCK_METHOD(void, FireObservers, (std::string_view path), (override));
-
-  size_t CountObserver(const std::string& path, PrefObserver* obs) {
-    auto observer_iterator = pref_observers()->find(path);
-    if (observer_iterator == pref_observers()->end())
-      return false;
-
-    size_t count = 0;
-    for (PrefObserver& existing_obs : observer_iterator->second) {
-      if (&existing_obs == obs)
-        count++;
-    }
-
-    return count;
-  }
+  MOCK_METHOD(void, NotifyCallbacks, (std::string_view path), (override));
 
   // Make public for tests below.
   using PrefNotifierImpl::OnPreferenceChanged;
   using PrefNotifierImpl::OnInitializationCompleted;
 };
 
-class PrefObserverMock : public PrefObserver {
+class PrefObserverMock {
  public:
-  MOCK_METHOD(void,
-              OnPreferenceChanged,
-              (PrefService*, std::string_view),
-              (override));
+  MOCK_METHOD2(OnPreferenceChanged, void(PrefService*, std::string_view));
 };
 
 // Test fixture class.
@@ -98,7 +81,7 @@
 
 TEST_F(PrefNotifierTest, OnPreferenceChanged) {
   MockPrefNotifier notifier(&pref_service_);
-  EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1);
+  EXPECT_CALL(notifier, NotifyCallbacks(kChangedPref)).Times(1);
   notifier.OnPreferenceChanged(kChangedPref);
 }
 
@@ -112,73 +95,15 @@
   notifier.OnInitializationCompleted(true);
 }
 
-TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) {
-  const char pref_name[] = "homepage";
-  const char pref_name2[] = "proxy";
-
-  MockPrefNotifier notifier(&pref_service_);
-  notifier.AddPrefObserver(pref_name, &obs1_);
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-
-  // Re-adding the same observer for the same pref doesn't change anything.
-  // This hits a DUMP_WILL_BE_NOTREACHED() which is fatal in non-official
-  // builds.
-#if defined(OFFICIAL_BUILD) && !DCHECK_IS_ON()
-  notifier.AddPrefObserver(pref_name, &obs1_);
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-#endif
-
-  // Ensure that we can add the same observer to a different pref.
-  notifier.AddPrefObserver(pref_name2, &obs1_);
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-
-  // Ensure that we can add another observer to the same pref.
-  notifier.AddPrefObserver(pref_name, &obs2_);
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-
-  // Ensure that we can remove all observers, and that removing a non-existent
-  // observer is harmless.
-  notifier.RemovePrefObserver(pref_name, &obs1_);
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-
-  notifier.RemovePrefObserver(pref_name, &obs2_);
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-
-  notifier.RemovePrefObserver(pref_name, &obs1_);
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-
-  notifier.RemovePrefObserver(pref_name2, &obs1_);
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
-  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
-}
-
-TEST_F(PrefNotifierTest, FireObservers) {
+TEST_F(PrefNotifierTest, NotifyCallbacks) {
   TestingPrefNotifierImpl notifier(&pref_service_);
-  notifier.AddPrefObserver(kChangedPref, &obs1_);
-  notifier.AddPrefObserver(kUnchangedPref, &obs1_);
+  base::CallbackListSubscription sub1_1 = notifier.AddPrefChangedCallback(
+      kChangedPref, base::BindRepeating(&PrefObserverMock::OnPreferenceChanged,
+                                        base::Unretained(&obs1_)));
+  base::CallbackListSubscription sub1_2 = notifier.AddPrefChangedCallback(
+      kUnchangedPref,
+      base::BindRepeating(&PrefObserverMock::OnPreferenceChanged,
+                          base::Unretained(&obs1_)));
 
   EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
   EXPECT_CALL(obs2_, OnPreferenceChanged(_, _)).Times(0);
@@ -186,8 +111,13 @@
   Mock::VerifyAndClearExpectations(&obs1_);
   Mock::VerifyAndClearExpectations(&obs2_);
 
-  notifier.AddPrefObserver(kChangedPref, &obs2_);
-  notifier.AddPrefObserver(kUnchangedPref, &obs2_);
+  base::CallbackListSubscription sub2_1 = notifier.AddPrefChangedCallback(
+      kChangedPref, base::BindRepeating(&PrefObserverMock::OnPreferenceChanged,
+                                        base::Unretained(&obs2_)));
+  base::CallbackListSubscription sub2_2 = notifier.AddPrefChangedCallback(
+      kUnchangedPref,
+      base::BindRepeating(&PrefObserverMock::OnPreferenceChanged,
+                          base::Unretained(&obs2_)));
 
   EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
   EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
@@ -196,7 +126,7 @@
   Mock::VerifyAndClearExpectations(&obs2_);
 
   // Make sure removing an observer from one pref doesn't affect anything else.
-  notifier.RemovePrefObserver(kChangedPref, &obs1_);
+  sub1_1 = base::CallbackListSubscription();
 
   EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
   EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
@@ -205,16 +135,13 @@
   Mock::VerifyAndClearExpectations(&obs2_);
 
   // Make sure removing an observer entirely doesn't affect anything else.
-  notifier.RemovePrefObserver(kUnchangedPref, &obs1_);
+  sub1_2 = base::CallbackListSubscription();
 
   EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
   EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
   notifier.OnPreferenceChanged(kChangedPref);
   Mock::VerifyAndClearExpectations(&obs1_);
   Mock::VerifyAndClearExpectations(&obs2_);
-
-  notifier.RemovePrefObserver(kChangedPref, &obs2_);
-  notifier.RemovePrefObserver(kUnchangedPref, &obs2_);
 }
 
 }  // namespace
diff --git a/components/prefs/pref_observer.h b/components/prefs/pref_observer.h
deleted file mode 100644
index bbc293a..0000000
--- a/components/prefs/pref_observer.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PREFS_PREF_OBSERVER_H_
-#define COMPONENTS_PREFS_PREF_OBSERVER_H_
-
-#include <string_view>
-
-class PrefService;
-
-// Used internally to the Prefs subsystem to pass preference change
-// notifications between PrefService, PrefNotifierImpl and
-// PrefChangeRegistrar.
-class PrefObserver {
- public:
-  virtual void OnPreferenceChanged(PrefService* service,
-                                   std::string_view pref_name) = 0;
-};
-
-#endif  // COMPONENTS_PREFS_PREF_OBSERVER_H_
diff --git a/components/prefs/pref_service.cc b/components/prefs/pref_service.cc
index dd7b1c8d..b2a0ac2 100644
--- a/components/prefs/pref_service.cc
+++ b/components/prefs/pref_service.cc
@@ -325,12 +325,10 @@
   return value;
 }
 
-void PrefService::AddPrefObserver(std::string_view path, PrefObserver* obs) {
-  pref_notifier_->AddPrefObserver(path, obs);
-}
-
-void PrefService::RemovePrefObserver(std::string_view path, PrefObserver* obs) {
-  pref_notifier_->RemovePrefObserver(path, obs);
+base::CallbackListSubscription PrefService::AddPrefChangedCallback(
+    std::string_view path,
+    PrefChangedCallback callback) {
+  return pref_notifier_->AddPrefChangedCallback(path, std::move(callback));
 }
 
 void PrefService::AddPrefInitObserver(base::OnceCallback<void(bool)> obs) {
@@ -360,12 +358,9 @@
   user_pref_store_->OnStoreDeletionFromDisk();
 }
 
-void PrefService::AddPrefObserverAllPrefs(PrefObserver* obs) {
-  pref_notifier_->AddPrefObserverAllPrefs(obs);
-}
-
-void PrefService::RemovePrefObserverAllPrefs(PrefObserver* obs) {
-  pref_notifier_->RemovePrefObserverAllPrefs(obs);
+base::CallbackListSubscription PrefService::AddAllPrefsChangedCallback(
+    PrefChangedCallback callback) {
+  return pref_notifier_->AddAllPrefsChangedCallback(std::move(callback));
 }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/components/prefs/pref_service.h b/components/prefs/pref_service.h
index 87bacd1..1c172657 100644
--- a/components/prefs/pref_service.h
+++ b/components/prefs/pref_service.h
@@ -41,7 +41,6 @@
 
 class PrefNotifier;
 class PrefNotifierImpl;
-class PrefObserver;
 class PrefRegistry;
 class PrefStore;
 #if BUILDFLAG(IS_ANDROID)
@@ -49,6 +48,7 @@
 #endif
 
 namespace base {
+class CallbackListSubscription;
 class FilePath;
 }
 
@@ -88,6 +88,9 @@
     PrefValueStore::PrefStoreType store;
   };
 
+  using PrefChangedCallback =
+      base::RepeatingCallback<void(PrefService*, std::string_view)>;
+
   // A helper class to store all the information associated with a preference.
   class COMPONENTS_PREFS_EXPORT Preference {
    public:
@@ -376,10 +379,9 @@
   // to tangentially cleanup data it may have saved outside the store.
   void OnStoreDeletionFromDisk();
 
-  // A low level function for registering an observer for every single
-  // preference changed notification. The caller must ensure that the observer
-  // remains valid as long as it is registered. Pointer ownership is not
-  // transferred.
+  // A low level function for registering a callback called for every single
+  // preference changed notification. The callback will be unregistered when
+  // the returned CallbackListSubscription is destroyed.
   //
   // Almost all calling code should use a PrefChangeRegistrar instead.
   //
@@ -388,8 +390,8 @@
   // of a "registrar" model makes it easy to forget to unregister. It is
   // really designed for integrating other notification systems, not for normal
   // observation.
-  void AddPrefObserverAllPrefs(PrefObserver* obs);
-  void RemovePrefObserverAllPrefs(PrefObserver* obs);
+  base::CallbackListSubscription AddAllPrefsChangedCallback(
+      PrefChangedCallback callback);
 
 #if BUILDFLAG(IS_ANDROID)
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
@@ -428,26 +430,24 @@
   friend class PrefServiceTest_WriteablePrefStoreFlags_Test;
   friend class prefs::ScopedDictionaryPrefUpdate;
 
-  // Registration of pref change observers must be done using the
+  // Registration of pref changed callbacks must be done using the
   // PrefChangeRegistrar, which is declared as a friend here to grant it
-  // access to the otherwise protected members Add/RemovePrefObserver.
+  // access to the otherwise protected member AddPrefChangedCallback.
   // PrefMember registers for preferences changes notification directly to
   // avoid the storage overhead of the registrar, so its base class must be
   // declared as a friend, too.
   friend class PrefChangeRegistrar;
   friend class subtle::PrefMemberBase;
 
-  // These are protected so they can only be accessed by the friend
+  // This method is protected so it can only be accessed by the friend
   // classes listed above.
   //
-  // If the pref at the given path changes, we call the observer's
-  // OnPreferenceChanged method. Note that observers should not call
-  // these methods directly but rather use a PrefChangeRegistrar to
-  // make sure the observer gets cleaned up properly.
-  //
-  // Virtual for testing.
-  virtual void AddPrefObserver(std::string_view path, PrefObserver* obs);
-  virtual void RemovePrefObserver(std::string_view path, PrefObserver* obs);
+  // Registers the callback to be invoked if the pref at the given path
+  // changes. The callback is automatically unregistered if the returned
+  // CallbackListSubscription is destroyed.
+  base::CallbackListSubscription AddPrefChangedCallback(
+      std::string_view path,
+      PrefChangedCallback callback);
 
   // A PrefStore::Observer which reports loading errors from
   // PersistentPrefStores after they are loaded. Usually this is only
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index 7b0d58e..0dffe6c 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -225,7 +225,7 @@
 
 BASE_FEATURE(kLocalIpAddressInEvents,
              "LocalIpAddressInEvents",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kLocalListsUseSBv5,
              "SafeBrowsingLocalListsUseSBv5",
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc
index f1de8aaa..1e53c1d8 100644
--- a/components/search/ntp_features.cc
+++ b/components/search/ntp_features.cc
@@ -356,6 +356,7 @@
     "NtpMostRelevantTabResumptionModuleDataParam";
 const char kNtpMostRelevantTabResumptionModuleMaxVisitsParam[] =
     "NtpMostRelevantTabResumptionModuleMaxVisitsParam";
+const char kNtpTabGroupsModuleDataParam[] = "NtpTabGroupsModuleDataParam";
 const char kNtpTabResumptionModuleCategoriesBlocklistParam[] =
     "NtpTabResumptionModuleCategoriesBlocklistParam";
 const char kNtpTabResumptionModuleDismissalDurationParam[] =
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h
index 392cb20..02870e7 100644
--- a/components/search/ntp_features.h
+++ b/components/search/ntp_features.h
@@ -149,6 +149,8 @@
 // Parameter determining the max visits to show.
 extern const char kNtpMostRelevantTabResumptionModuleMaxVisitsParam[];
 extern const char kNtpRealboxWidthBehaviorParam[];
+// Parameter determining the type of tab groups data to render.
+extern const char kNtpTabGroupsModuleDataParam[];
 // Parameter for determining the categories a tab must not fall into
 // to be shown.
 extern const char kNtpTabResumptionModuleCategoriesBlocklistParam[];
diff --git a/components/search_engines/android/template_url_service_android.cc b/components/search_engines/android/template_url_service_android.cc
index 8fdf398..451cc58 100644
--- a/components/search_engines/android/template_url_service_android.cc
+++ b/components/search_engines/android/template_url_service_android.cc
@@ -365,7 +365,7 @@
   TemplateURL* template_url =
       template_url_service_->GetTemplateURLForKeyword(keyword);
   if (!template_url)
-    return base::android::ScopedJavaLocalRef<jstring>(env, nullptr);
+    return base::android::ScopedJavaLocalRef<jstring>::Adopt(env, nullptr);
   std::string url(template_url->url_ref().ReplaceSearchTerms(
       TemplateURLRef::SearchTermsArgs(u"query"),
       template_url_service_->search_terms_data()));
@@ -510,7 +510,7 @@
   const TemplateURL* default_search_provider =
       template_url_service_->GetDefaultSearchProvider();
   if (default_search_provider == nullptr) {
-    return base::android::ScopedJavaLocalRef<jobject>(env, nullptr);
+    return base::android::ScopedJavaLocalRef<jobject>::Adopt(env, nullptr);
   }
   return CreateTemplateUrlAndroid(env, default_search_provider);
 }
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index f67902e..50a99946 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -294,7 +294,8 @@
     std::string target_lang,
     std::string fluent_languages,
     std::string related_searches_stamp,
-    bool apply_lang_hint)
+    bool apply_lang_hint,
+    bool use_snippet_as_subtitle)
     : version(version),
       contextual_cards_version(contextual_cards_version),
       home_country(home_country),
@@ -305,7 +306,8 @@
       target_lang(target_lang),
       fluent_languages(fluent_languages),
       related_searches_stamp(related_searches_stamp),
-      apply_lang_hint(apply_lang_hint) {}
+      apply_lang_hint(apply_lang_hint),
+      use_snippet_as_subtitle(use_snippet_as_subtitle) {}
 
 TemplateURLRef::SearchTermsArgs::ContextualSearchParams::ContextualSearchParams(
     const ContextualSearchParams& other) = default;
@@ -1128,6 +1130,8 @@
           args.push_back("ctxsl_rs=" + params.related_searches_stamp);
         if (params.apply_lang_hint)
           args.push_back("ctxsl_applylh=1");
+        if (params.use_snippet_as_subtitle)
+          args.push_back("ctxs_usas=1");
 
         HandleReplacement(std::string(), base::JoinString(args, "&"),
                           replacement, &url);
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h
index bf5e4b9f..176918e 100644
--- a/components/search_engines/template_url.h
+++ b/components/search_engines/template_url.h
@@ -124,6 +124,8 @@
       // translation is forced using |source_lang|. Note that this only supports
       // Partial Translate and so may only be enabled for select clients on the
       // server.
+      // The |use_snippet_as_subtitle| specifies whether or not the entity
+      // snippet should be used as the subtitle of the card.
       ContextualSearchParams(int version,
                              int contextual_cards_version,
                              std::string home_country,
@@ -134,7 +136,8 @@
                              std::string target_lang,
                              std::string fluent_languages,
                              std::string related_searches_stamp,
-                             bool apply_lang_hint);
+                             bool apply_lang_hint,
+                             bool use_snippet_as_subtitle);
       ContextualSearchParams(const ContextualSearchParams& other);
       ~ContextualSearchParams();
 
@@ -183,6 +186,9 @@
 
       // Whether hinted language detection should be used on the backend.
       bool apply_lang_hint = false;
+
+      // Whether the snippet should be used as the subtitle.
+      bool use_snippet_as_subtitle = false;
     };
 
     // Estimates dynamic memory usage.
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc
index 928d9809..f96bc07 100644
--- a/components/search_engines/template_url_unittest.cc
+++ b/components/search_engines/template_url_unittest.cc
@@ -2240,7 +2240,7 @@
   // event.
   TemplateURLRef::SearchTermsArgs::ContextualSearchParams params(
       2, 1, std::string(), 0, 0, false, std::string(), std::string(),
-      std::string(), std::string(), false);
+      std::string(), std::string(), false, false);
   search_terms_args.contextual_search_params = params;
   result = url.url_ref().ReplaceSearchTerms(search_terms_args,
                                             search_terms_data_);
@@ -2254,7 +2254,7 @@
   search_terms_args.contextual_search_params =
       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
           2, 2, "CH", 1657713458, 5, false, std::string(), std::string(),
-          std::string(), std::string(), false);
+          std::string(), std::string(), false, false);
   result =
       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
 
@@ -2271,7 +2271,7 @@
   search_terms_args.contextual_search_params =
       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
-          std::string(), std::string(), false);
+          std::string(), std::string(), false, false);
   result =
       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
   // Find our param.
@@ -2282,7 +2282,7 @@
   search_terms_args.contextual_search_params =
       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
           2, 1, std::string(), 0, 0, true, "es", "de", std::string(),
-          std::string(), false);
+          std::string(), false, false);
   result =
       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
   // Find our params.
@@ -2295,7 +2295,7 @@
   search_terms_args.contextual_search_params =
       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
-          "es,de", std::string(), false);
+          "es,de", std::string(), false, false);
   result =
       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
   // Find our param.  These may actually be URL encoded.
@@ -2306,7 +2306,7 @@
   search_terms_args.contextual_search_params =
       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
-          std::string(), "1RbCu", false);
+          std::string(), "1RbCu", false, false);
   result =
       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
   // Find our param.
@@ -2317,12 +2317,22 @@
   search_terms_args.contextual_search_params =
       TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
           2, 1, std::string(), 0, 0, true, std::string(), std::string(),
-          std::string(), std::string(), true);
+          std::string(), std::string(), true, false);
   result =
       url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
   // Find our param.
   size_t ctxsl_applylh = result.find("&ctxsl_applylh=1");
   EXPECT_NE(ctxsl_applylh, std::string::npos);
+
+  // Test use_snippet_as_subtitle.
+  search_terms_args.contextual_search_params =
+      TemplateURLRef::SearchTermsArgs::ContextualSearchParams(
+          2, 1, std::string(), 0, 0, true, std::string(), std::string(),
+          std::string(), std::string(), false, true);
+  result =
+      url.url_ref().ReplaceSearchTerms(search_terms_args, search_terms_data_);
+  size_t ctxs_usas = result.find("&ctxs_usas=1");
+  EXPECT_NE(ctxs_usas, std::string::npos);
 }
 
 TEST_F(TemplateURLTest, GenerateKeyword) {
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc
index f36395f..262cd6fa 100644
--- a/components/signin/public/identity_manager/identity_manager.cc
+++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -487,7 +487,7 @@
   base::android::ScopedJavaLocalRef<jclass> coreaccountinfo_clazz =
       base::android::GetClass(
           env, "org/chromium/components/signin/base/CoreAccountInfo");
-  base::android::ScopedJavaLocalRef<jobjectArray> array(
+  auto array = base::android::ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(accounts.size(), coreaccountinfo_clazz.obj(),
                                nullptr));
   base::android::CheckException(env);
diff --git a/components/signin/public/identity_manager/identity_mutator.cc b/components/signin/public/identity_manager/identity_mutator.cc
index 9dfafd0c..94695435 100644
--- a/components/signin/public/identity_manager/identity_mutator.cc
+++ b/components/signin/public/identity_manager/identity_mutator.cc
@@ -78,7 +78,7 @@
   std::vector<AccountInfo> accounts;
   for (size_t i = 0;
        i < base::android::SafeGetArrayLength(env, j_account_infos); i++) {
-    base::android::ScopedJavaLocalRef<jobject> account_info_java(
+    auto account_info_java = base::android::ScopedJavaLocalRef<jobject>::Adopt(
         env, env->GetObjectArrayElement(j_account_infos.obj(), i));
     accounts.push_back(ConvertFromJavaAccountInfo(env, account_info_java));
   }
diff --git a/components/spellcheck/browser/spellchecker_session_bridge_android.cc b/components/spellcheck/browser/spellchecker_session_bridge_android.cc
index dae6275..df74531 100644
--- a/components/spellcheck/browser/spellchecker_session_bridge_android.cc
+++ b/components/spellcheck/browser/spellchecker_session_bridge_android.cc
@@ -87,9 +87,10 @@
 
   std::vector<SpellCheckResult> results;
   for (size_t i = 0; i < offsets.size(); i++) {
-    base::android::ScopedJavaLocalRef<jobjectArray> suggestions_for_word_array(
-        env, static_cast<jobjectArray>(
-                 env->GetObjectArrayElement(suggestions_array.obj(), i)));
+    auto suggestions_for_word_array =
+        base::android::ScopedJavaLocalRef<jobjectArray>::Adopt(
+            env, static_cast<jobjectArray>(
+                     env->GetObjectArrayElement(suggestions_array.obj(), i)));
     std::vector<std::u16string> suggestions_for_word;
     base::android::AppendJavaStringArrayToStringVector(
         env, suggestions_for_word_array, &suggestions_for_word);
diff --git a/components/supervised_user/OWNERS b/components/supervised_user/OWNERS
index 898f9d2..31380466 100644
--- a/components/supervised_user/OWNERS
+++ b/components/supervised_user/OWNERS
@@ -7,7 +7,10 @@
 chrome-family-kids-reviews@google.com
 
 # ChromeOS
+# TODO(433734945): Remove agawronska after transition completes.
 agawronska@chromium.org    #{LAST_RESORT_SUGGESTION}
+zhangwenyu@google.com      #{LAST_RESORT_SUGGESTION}
+longbowei@google.com       #{LAST_RESORT_SUGGESTION}
 
 # Chrome Browser
 anthie@google.com       #{LAST_RESORT_SUGGESTION}
diff --git a/components/sync/android/sync_service_android_bridge.cc b/components/sync/android/sync_service_android_bridge.cc
index 9e17c30..1ecc60f6 100644
--- a/components/sync/android/sync_service_android_bridge.cc
+++ b/components/sync/android/sync_service_android_bridge.cc
@@ -108,7 +108,7 @@
   base::android::ScopedJavaLocalRef<jclass> localdatadescription_clazz =
       base::android::GetClass(
           env, "org/chromium/components/sync/LocalDataDescription");
-  base::android::ScopedJavaLocalRef<jobjectArray> array(
+  auto array = base::android::ScopedJavaLocalRef<jobjectArray>::Adopt(
       env, env->NewObjectArray(local_data_descriptions.size(),
                                localdatadescription_clazz.obj(), nullptr));
   base::android::CheckException(env);
diff --git a/components/sync/service/sync_client.h b/components/sync/service/sync_client.h
index 3f77185..85576c0 100644
--- a/components/sync/service/sync_client.h
+++ b/components/sync/service/sync_client.h
@@ -6,7 +6,6 @@
 #define COMPONENTS_SYNC_SERVICE_SYNC_CLIENT_H_
 
 #include "base/files/file_path.h"
-#include "base/functional/callback_forward.h"
 #include "base/memory/ref_counted.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/base/extensions_activity.h"
@@ -59,18 +58,6 @@
   // Returns whether custom passphrase is allowed for the current user.
   virtual bool IsCustomPassphraseAllowed() = 0;
 
-  // Necessary but not sufficient condition for password sync to be enabled,
-  // i.e. it influences the value of SyncUserSettings::GetSelectedTypes().
-  // TODO(crbug.com/328190573): Remove this and SetPasswordSyncAllowedChangeCb()
-  // below when the local UPM migration is gone.
-  virtual bool IsPasswordSyncAllowed() = 0;
-
-  // Causes `cb` to be invoked whenever the value of IsPasswordSyncAllowed()
-  // changes. Spurious invocations can occur too. This method must be called at
-  // most once.
-  virtual void SetPasswordSyncAllowedChangeCb(
-      const base::RepeatingClosure& cb) = 0;
-
   // Registers synthetic field trials corresponding to autoupgrading users to
   // trusted vault passphrase type. `group` must be valid. Must be invoked at
   // most once.
diff --git a/components/sync/service/sync_prefs.cc b/components/sync/service/sync_prefs.cc
index 03bbe4f..4aa09a0 100644
--- a/components/sync/service/sync_prefs.cc
+++ b/components/sync/service/sync_prefs.cc
@@ -295,10 +295,6 @@
     }
   }
 
-  if (!password_sync_allowed_) {
-    selected_types.Remove(UserSelectableType::kPasswords);
-  }
-
   return selected_types;
 }
 
@@ -321,10 +317,6 @@
     }
   }
 
-  if (!password_sync_allowed_) {
-    selected_types.Remove(UserSelectableType::kPasswords);
-  }
-
   return selected_types;
 }
 
@@ -1090,17 +1082,6 @@
   }
 }
 
-void SyncPrefs::SetPasswordSyncAllowed(bool allowed) {
-  if (password_sync_allowed_ == allowed) {
-    return;
-  }
-
-  password_sync_allowed_ = allowed;
-  for (SyncPrefObserver& observer : sync_pref_observers_) {
-    observer.OnSelectedTypesPrefChange();
-  }
-}
-
 bool SyncPrefs::IsTypeSelectedByDefaultInTransportMode(
     UserSelectableType type,
     const GaiaId& gaia_id) const {
diff --git a/components/sync/service/sync_prefs.h b/components/sync/service/sync_prefs.h
index c7470f9a..72c7771b 100644
--- a/components/sync/service/sync_prefs.h
+++ b/components/sync/service/sync_prefs.h
@@ -257,12 +257,6 @@
   // temporary state from the above migration.
   void MarkPartialSyncToSigninMigrationFullyDone();
 
-  // Setting to false causes GetSelectedTypesForSyncingUser() and
-  // GetSelectedTypesForAccount() to not include passwords, no matter the
-  // underlying user settings.
-  // TODO(crbug.com/328190573): Remove this when local UPM migration is gone.
-  void SetPasswordSyncAllowed(bool allowed);
-
   static void MigrateAutofillWalletImportEnabledPref(PrefService* pref_service);
 
   // Copies the global versions of the selected-types prefs (used for syncing
@@ -317,8 +311,6 @@
 
   bool batch_updating_selected_types_ = false;
 
-  bool password_sync_allowed_ = true;
-
   // Caches the value of the kEnableLocalSyncBackend pref to avoid it flipping
   // during the lifetime of the service.
   const bool local_sync_enabled_;
diff --git a/components/sync/service/sync_prefs_unittest.cc b/components/sync/service/sync_prefs_unittest.cc
index 9eb02c54..01433ca8 100644
--- a/components/sync/service/sync_prefs_unittest.cc
+++ b/components/sync/service/sync_prefs_unittest.cc
@@ -762,41 +762,6 @@
   EXPECT_EQ(0, sync_prefs_->GetPassphrasePromptMutedProductVersion());
 }
 
-TEST_F(SyncPrefsTest, PasswordSyncAllowed_DefaultValue) {
-  // Passwords is in its default state. For syncing users, it's enabled. For
-  // non-syncing users, it depends on the platform.
-  ASSERT_TRUE(sync_prefs_->GetSelectedTypesForSyncingUser().Has(
-      UserSelectableType::kPasswords));
-  StrictMock<MockSyncPrefObserver> observer;
-  sync_prefs_->AddObserver(&observer);
-  EXPECT_CALL(observer, OnSelectedTypesPrefChange);
-
-  sync_prefs_->SetPasswordSyncAllowed(false);
-
-  EXPECT_FALSE(sync_prefs_->GetSelectedTypesForSyncingUser().Has(
-      UserSelectableType::kPasswords));
-  EXPECT_FALSE(sync_prefs_->GetSelectedTypesForAccount(gaia_id_).Has(
-      UserSelectableType::kPasswords));
-  sync_prefs_->RemoveObserver(&observer);
-}
-
-TEST_F(SyncPrefsTest, PasswordSyncAllowed_ExplicitValue) {
-  // Make passwords explicitly enabled (no default value).
-  sync_prefs_->SetSelectedTypesForSyncingUser(
-      /*keep_everything_synced=*/false,
-      /*registered_types=*/UserSelectableTypeSet::All(),
-      /*selected_types=*/{UserSelectableType::kPasswords});
-  sync_prefs_->SetSelectedTypeForAccount(UserSelectableType::kPasswords, true,
-                                         gaia_id_);
-
-  sync_prefs_->SetPasswordSyncAllowed(false);
-
-  EXPECT_FALSE(sync_prefs_->GetSelectedTypesForSyncingUser().Has(
-      UserSelectableType::kPasswords));
-  EXPECT_FALSE(sync_prefs_->GetSelectedTypesForAccount(gaia_id_).Has(
-      UserSelectableType::kPasswords));
-}
-
 enum BooleanPrefState { PREF_FALSE, PREF_TRUE, PREF_UNSET };
 
 // Similar to SyncPrefsTest, but does not create a SyncPrefs instance. This lets
diff --git a/components/sync/service/sync_service_impl.cc b/components/sync/service/sync_service_impl.cc
index 68a923d..046c649a 100644
--- a/components/sync/service/sync_service_impl.cc
+++ b/components/sync/service/sync_service_impl.cc
@@ -238,11 +238,6 @@
   // shouldn't be instantiated.
   DCHECK(IsSyncAllowedByFlag());
 
-  sync_prefs_.SetPasswordSyncAllowed(sync_client_->IsPasswordSyncAllowed());
-  // base::Unretained() is safe, `this` outlives `sync_client_`.
-  sync_client_->SetPasswordSyncAllowedChangeCb(base::BindRepeating(
-      &SyncServiceImpl::OnPasswordSyncAllowedChanged, base::Unretained(this)));
-
   sync_stopped_reporter_ = std::make_unique<SyncStoppedReporter>(
       sync_service_url_, MakeUserAgentForSync(channel_), url_loader_factory_);
 
@@ -1996,11 +1991,6 @@
   return DataTypeDownloadStatus::kUpToDate;
 }
 
-void SyncServiceImpl::OnPasswordSyncAllowedChanged() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  sync_prefs_.SetPasswordSyncAllowed(sync_client_->IsPasswordSyncAllowed());
-}
-
 void SyncServiceImpl::CacheTrustedVaultDebugInfoToPrefsFromEngine() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   CHECK(engine_);
diff --git a/components/sync/service/sync_service_impl.h b/components/sync/service/sync_service_impl.h
index 96ef73f5..0d76b6a 100644
--- a/components/sync/service/sync_service_impl.h
+++ b/components/sync/service/sync_service_impl.h
@@ -371,8 +371,6 @@
   // type.
   void MaybeRecordTrustedVaultHistograms();
 
-  void OnPasswordSyncAllowedChanged();
-
   // Updates PrefService (SyncPrefs) to cache the last known value for trusted
   // vault AutoUpgradeDebugInfo. It also notifies SyncClient.
   void CacheTrustedVaultDebugInfoToPrefsFromEngine();
diff --git a/components/sync/service/sync_service_impl_unittest.cc b/components/sync/service/sync_service_impl_unittest.cc
index 4f4b576..49b0426 100644
--- a/components/sync/service/sync_service_impl_unittest.cc
+++ b/components/sync/service/sync_service_impl_unittest.cc
@@ -195,7 +195,6 @@
     std::unique_ptr<SyncClientMock> sync_client =
         sync_service_impl_bundle_.CreateSyncClientMock();
     sync_client_ = sync_client.get();
-    ON_CALL(*sync_client, IsPasswordSyncAllowed).WillByDefault(Return(true));
     ON_CALL(*sync_client, GetIdentityManager)
         .WillByDefault(Return(identity_manager()));
 
diff --git a/components/sync/test/sync_client_mock.h b/components/sync/test/sync_client_mock.h
index a56eb8e..481047a3 100644
--- a/components/sync/test/sync_client_mock.h
+++ b/components/sync/test/sync_client_mock.h
@@ -39,11 +39,6 @@
               (override));
   MOCK_METHOD(SyncEngineFactory*, GetSyncEngineFactory, (), (override));
   MOCK_METHOD(bool, IsCustomPassphraseAllowed, (), (override));
-  MOCK_METHOD(bool, IsPasswordSyncAllowed, (), (override));
-  MOCK_METHOD(void,
-              SetPasswordSyncAllowedChangeCb,
-              (const base::RepeatingClosure&),
-              (override));
   MOCK_METHOD(void,
               RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial,
               (const TrustedVaultAutoUpgradeSyntheticFieldTrialGroup&),
diff --git a/components/tabs/BUILD.gn b/components/tabs/BUILD.gn
index b9f658c1..ef70418 100644
--- a/components/tabs/BUILD.gn
+++ b/components/tabs/BUILD.gn
@@ -13,6 +13,7 @@
     "public/tab_collection.h",
     "public/tab_group.h",
     "public/tab_group_tab_collection.h",
+    "public/tab_handle_factory.h",
     "public/tab_interface.h",
     "public/tab_strip_collection.h",
     "public/unpinned_tab_collection.h",
@@ -56,6 +57,7 @@
     "impl/tab_collection_storage.cc",
     "impl/tab_group.cc",
     "impl/tab_group_tab_collection.cc",
+    "impl/tab_handle_factory.cc",
     "impl/tab_strip_collection.cc",
     "impl/unpinned_tab_collection.cc",
   ]
@@ -92,9 +94,7 @@
   # TODO(crbug.com/415965103): tab_collection_storage_unittest.cc
   # TODO(crbug.com/415965106): tab_iterator_unittest.cc
   sources = [
-    "impl/tab_handle_factory.cc",
     "public/supports_handles_unittest.cc",
-    "public/tab_handle_factory.h",
     "public/tab_handle_factory_unittest.cc",
   ]
 
diff --git a/components/tabs/public/tab_interface.h b/components/tabs/public/tab_interface.h
index 14ed0a9a..858817cd 100644
--- a/components/tabs/public/tab_interface.h
+++ b/components/tabs/public/tab_interface.h
@@ -14,7 +14,7 @@
 #include "build/build_config.h"
 #include "build/buildflag.h"
 #include "components/tab_groups/tab_group_id.h"
-#include "components/tabs/public/supports_handles.h"
+#include "components/tabs/public/tab_handle_factory.h"
 
 namespace ui {
 class UnownedUserDataHost;
@@ -46,8 +46,6 @@
   virtual ~ScopedTabModalUI() = default;
 };
 
-DECLARE_HANDLE_FACTORY(TabInterface);
-
 // TODO(crbug.com/404889112): This interface will be reused for Android as part
 // of the effort to share tab collections between desktop and Android. Some
 // features of TabInterface are unsupported on Android. A buildflag is used to
@@ -59,7 +57,7 @@
 // Ping erikchen for assistance if this class does not have the functionality
 // your feature needs. This comment will be deleted after there are 10+ features
 // in TabFeatures.
-class TabInterface : public SupportsHandles<TabInterfaceHandleFactory> {
+class TabInterface : public SupportsTabHandles {
  public:
   // This method exists to ease the transition from WebContents to TabInterface.
   // This method should only be called on instances of WebContents that are
diff --git a/components/test/data/optimization_guide/media_data/video.html b/components/test/data/optimization_guide/media_data/video.html
new file mode 100644
index 0000000..45a6380
--- /dev/null
+++ b/components/test/data/optimization_guide/media_data/video.html
@@ -0,0 +1,36 @@
+<html>
+<head>
+  <title>Test page showing a video</title>
+</head>
+<body>
+<video id="video" src="video.webm"></video>
+</body>
+<script>
+  const video = document.getElementById('video');
+
+  // These functions will be called by the browser test.
+  function play() {
+    video.play();
+  }
+
+  function pause() {
+    video.pause();
+  }
+
+  function setupMetadata() {
+    navigator.mediaSession.metadata = new MediaMetadata({
+      title: "test title",
+      artist: "test artist",
+      album: "test album",
+    });
+  }
+
+  function setupPosition() {
+    navigator.mediaSession.setPositionState({
+      duration: 10.0,
+      position: 5.0,
+      playbackRate: 1.0
+    });
+  }
+</script>
+</html>
diff --git a/components/test/data/optimization_guide/media_data/video.webm b/components/test/data/optimization_guide/media_data/video.webm
new file mode 100644
index 0000000..d1721ac
--- /dev/null
+++ b/components/test/data/optimization_guide/media_data/video.webm
Binary files differ
diff --git a/components/test/data/optimization_guide/media_data/video_in_iframe.html b/components/test/data/optimization_guide/media_data/video_in_iframe.html
new file mode 100644
index 0000000..be42459
--- /dev/null
+++ b/components/test/data/optimization_guide/media_data/video_in_iframe.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+  <title>Test page showing a video in an iframe</title>
+</head>
+<body>
+<iframe id="iframe" src="./video.html"></iframe>
+</body>
+<script>
+  // These functions will be called by the browser test.
+  function play() {
+    document.getElementById('iframe').contentWindow.play();
+  }
+
+  function setupPosition() {
+    document.getElementById('iframe').contentWindow.setupPosition();
+  }
+</script>
+</html>
diff --git a/components/test/data/optimization_guide/unit_tests_bundle_data.filelist b/components/test/data/optimization_guide/unit_tests_bundle_data.filelist
index e41657f..6baef98 100644
--- a/components/test/data/optimization_guide/unit_tests_bundle_data.filelist
+++ b/components/test/data/optimization_guide/unit_tests_bundle_data.filelist
@@ -23,6 +23,9 @@
 //components/test/data/optimization_guide/iframe_same_site.html
 //components/test/data/optimization_guide/invalid_model.crx3
 //components/test/data/optimization_guide/label_not_actionable.html
+//components/test/data/optimization_guide/media_data/video.html
+//components/test/data/optimization_guide/media_data/video.webm
+//components/test/data/optimization_guide/media_data/video_in_iframe.html
 //components/test/data/optimization_guide/page_topics_128_model.tflite
 //components/test/data/optimization_guide/paid_content.html
 //components/test/data/optimization_guide/paragraph.html
diff --git a/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm b/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm
index 563dc4b..c33bb098 100644
--- a/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm
+++ b/components/trusted_vault/icloud_keychain_recovery_factor_unittest.mm
@@ -26,9 +26,9 @@
 #include "components/trusted_vault/trusted_vault_connection.h"
 #include "components/trusted_vault/trusted_vault_crypto.h"
 #include "components/trusted_vault/trusted_vault_server_constants.h"
-#include "crypto/apple_keychain_v2.h"
-#include "crypto/fake_apple_keychain_v2.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -438,7 +438,7 @@
       nullptr;
   std::unique_ptr<ICloudKeychainRecoveryFactor> recovery_factor_;
 
-  crypto::ScopedFakeAppleKeychainV2 fake_keychain_{kKeychainAccessGroup};
+  crypto::apple::ScopedFakeKeychainV2 fake_keychain_{kKeychainAccessGroup};
   base::test::TaskEnvironment task_environment_;
 };
 
diff --git a/components/trusted_vault/icloud_recovery_key_mac.mm b/components/trusted_vault/icloud_recovery_key_mac.mm
index 29764d2..c2f35d0 100644
--- a/components/trusted_vault/icloud_recovery_key_mac.mm
+++ b/components/trusted_vault/icloud_recovery_key_mac.mm
@@ -22,7 +22,7 @@
 #include "base/task/thread_pool.h"
 #include "components/trusted_vault/securebox.h"
 #include "components/trusted_vault/trusted_vault_server_constants.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 
 namespace trusted_vault {
 
@@ -92,7 +92,7 @@
     CFToNSPtrCast(kSecReturnAttributes) : @YES,
   }];
   base::apple::ScopedCFTypeRef<CFTypeRef> result;
-  OSStatus status = crypto::AppleKeychainV2::GetInstance().ItemCopyMatching(
+  OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemCopyMatching(
       NSToCFPtrCast(query), result.InitializeInto());
   std::vector<std::unique_ptr<trusted_vault::SecureBoxKeyPair>> ret;
   if (status == errSecItemNotFound) {
@@ -188,9 +188,9 @@
     CFToNSPtrCast(kSecAttrAccount) : EncodePublicKey(key->public_key()),
     CFToNSPtrCast(kSecValueData) : EncodePrivateKey(key->private_key()),
   }];
-  OSStatus result =
-      crypto::AppleKeychainV2::GetInstance().ItemAdd(NSToCFPtrCast(attributes),
-                                                     /*result=*/nil);
+  OSStatus result = crypto::apple::KeychainV2::GetInstance().ItemAdd(
+      NSToCFPtrCast(attributes),
+      /*result=*/nil);
   if (result != errSecSuccess) {
     LOG(ERROR) << "Could not store iCloud recovery key: " << result;
     return nullptr;
diff --git a/components/trusted_vault/icloud_recovery_key_mac_unittest.mm b/components/trusted_vault/icloud_recovery_key_mac_unittest.mm
index 3d99346..d01aaae 100644
--- a/components/trusted_vault/icloud_recovery_key_mac_unittest.mm
+++ b/components/trusted_vault/icloud_recovery_key_mac_unittest.mm
@@ -21,9 +21,9 @@
 #include "base/test/test_future.h"
 #include "components/trusted_vault/securebox.h"
 #include "components/trusted_vault/trusted_vault_server_constants.h"
-#include "crypto/apple_keychain_v2.h"
-#include "crypto/fake_apple_keychain_v2.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -75,7 +75,7 @@
   }
 
  protected:
-  crypto::ScopedFakeAppleKeychainV2 fake_keychain_{kKeychainAccessGroup};
+  crypto::apple::ScopedFakeKeychainV2 fake_keychain_{kKeychainAccessGroup};
   base::test::TaskEnvironment task_environment_;
 };
 
diff --git a/components/ukm/android/ukm_recorder.cc b/components/ukm/android/ukm_recorder.cc
index 5f370a6..c0d5ee8 100644
--- a/components/ukm/android/ukm_recorder.cc
+++ b/components/ukm/android/ukm_recorder.cc
@@ -47,8 +47,10 @@
   CHECK_GE(jlength, 0) << "Invalid array length: " << jlength;
   size_t length = static_cast<size_t>(std::max(0, jlength));
   for (size_t i = 0; i < length; ++i) {
-    jni_zero::ScopedJavaLocalRef<jobject> j_metric(
-        env, static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
+    jni_zero::ScopedJavaLocalRef<jobject> j_metric =
+        jni_zero::ScopedJavaLocalRef<jobject>::Adopt(
+            env,
+            static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
     out->emplace_back(ConvertJavaMetric(env, j_metric));
   }
 }
diff --git a/components/user_education/common/BUILD.gn b/components/user_education/common/BUILD.gn
index 565923a..5fe5291 100644
--- a/components/user_education/common/BUILD.gn
+++ b/components/user_education/common/BUILD.gn
@@ -57,6 +57,8 @@
     "ntp_promo/ntp_promo_controller.cc",
     "ntp_promo/ntp_promo_controller.h",
     "ntp_promo/ntp_promo_identifier.h",
+    "ntp_promo/ntp_promo_order.cc",
+    "ntp_promo/ntp_promo_order.h",
     "ntp_promo/ntp_promo_registry.cc",
     "ntp_promo/ntp_promo_registry.h",
     "ntp_promo/ntp_promo_specification.cc",
@@ -136,6 +138,7 @@
     "help_bubble/help_bubble_factory_registry_unittest.cc",
     "new_badge/new_badge_controller_unittest.cc",
     "ntp_promo/ntp_promo_controller_unittest.cc",
+    "ntp_promo/ntp_promo_order_unittest.cc",
     "ntp_promo/ntp_promo_registry_unittest.cc",
     "product_messaging_controller_unittest.cc",
     "session/user_education_session_manager_unittest.cc",
diff --git a/components/user_education/common/ntp_promo/ntp_promo_controller.cc b/components/user_education/common/ntp_promo/ntp_promo_controller.cc
index 6632672..248f1ebe 100644
--- a/components/user_education/common/ntp_promo/ntp_promo_controller.cc
+++ b/components/user_education/common/ntp_promo/ntp_promo_controller.cc
@@ -6,6 +6,8 @@
 
 #include "base/time/time.h"
 #include "components/user_education/common/ntp_promo/ntp_promo_identifier.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_order.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_registry.h"
 #include "components/user_education/common/user_education_data.h"
 #include "components/user_education/common/user_education_storage_service.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -14,6 +16,7 @@
 
 namespace {
 
+constexpr int kNumSessionsBetweenTopPromoRotation = 3;
 constexpr base::TimeDelta kCompletedPromoShowDuration = base::Days(7);
 
 }  // namespace
@@ -43,7 +46,11 @@
 NtpPromoController::NtpPromoController(
     NtpPromoRegistry& registry,
     UserEducationStorageService& storage_service)
-    : registry_(registry), storage_service_(storage_service) {}
+    : registry_(registry), storage_service_(storage_service) {
+  // TODO(crbug.com/421398754): Allow Finch to override ordering criteria.
+  order_policy_ = std::make_unique<NtpPromoOrderPolicy>(
+      registry, storage_service, kNumSessionsBetweenTopPromoRotation);
+}
 
 NtpPromoController::~NtpPromoController() = default;
 
@@ -60,7 +67,8 @@
 }
 
 NtpShowablePromos NtpPromoController::GenerateShowablePromos(Profile* profile) {
-  NtpShowablePromos showable_promos;
+  std::vector<NtpPromoIdentifier> pending_promo_ids;
+  std::vector<NtpPromoIdentifier> completed_promo_ids;
   const auto now = base::Time::Now();
 
   for (const auto& id : registry_->GetNtpPromoIdentifiers()) {
@@ -100,16 +108,17 @@
       continue;
     }
 
-    NtpShowablePromo promo(
-        spec->id(), spec->content().icon_name(),
-        l10n_util::GetStringUTF8(spec->content().body_text_string_id()),
-        l10n_util::GetStringUTF8(
-            spec->content().action_button_text_string_id()));
-    (prefs.completed.is_null() ? showable_promos.pending
-                               : showable_promos.completed)
-        .push_back(std::move(promo));
+    (prefs.completed.is_null() ? pending_promo_ids : completed_promo_ids)
+        .push_back(id);
   }
 
+  pending_promo_ids = order_policy_->OrderPendingPromos(pending_promo_ids);
+  completed_promo_ids =
+      order_policy_->OrderCompletedPromos(completed_promo_ids);
+
+  NtpShowablePromos showable_promos;
+  showable_promos.pending = MakeShowablePromos(pending_promo_ids);
+  showable_promos.completed = MakeShowablePromos(completed_promo_ids);
   return showable_promos;
 }
 
@@ -151,4 +160,19 @@
   }
 }
 
+std::vector<NtpShowablePromo> NtpPromoController::MakeShowablePromos(
+    const std::vector<NtpPromoIdentifier>& ids) {
+  std::vector<NtpShowablePromo> promos;
+  for (const auto& id : ids) {
+    const auto* spec = registry_->GetNtpPromoSpecification(id);
+    promos.emplace_back(
+
+        spec->id(), spec->content().icon_name(),
+        l10n_util::GetStringUTF8(spec->content().body_text_string_id()),
+        l10n_util::GetStringUTF8(
+            spec->content().action_button_text_string_id()));
+  }
+  return promos;
+}
+
 }  // namespace user_education
diff --git a/components/user_education/common/ntp_promo/ntp_promo_controller.h b/components/user_education/common/ntp_promo/ntp_promo_controller.h
index ca2d98ac43..fd9a2328 100644
--- a/components/user_education/common/ntp_promo/ntp_promo_controller.h
+++ b/components/user_education/common/ntp_promo/ntp_promo_controller.h
@@ -10,17 +10,18 @@
 #include "base/auto_reset.h"
 #include "base/feature_list.h"
 #include "base/memory/raw_ref.h"
+#include "base/time/time.h"
 #include "components/user_education/common/ntp_promo/ntp_promo_identifier.h"
-#include "components/user_education/common/ntp_promo/ntp_promo_registry.h"
-#include "components/user_education/common/ntp_promo/ntp_promo_specification.h"
-#include "components/user_education/common/user_education_data.h"
-#include "components/user_education/common/user_education_storage_service.h"
 
 class BrowserWindowInterface;
 class Profile;
 
 namespace user_education {
 
+class NtpPromoRegistry;
+class NtpPromoOrderPolicy;
+class UserEducationStorageService;
+
 // The contents of a promo as it will be shown in the NTP.
 struct NtpShowablePromo {
   NtpShowablePromo();
@@ -87,8 +88,14 @@
   // Updates the data on the promo shown in the top spot.
   void OnPromoShownInTopSpot(NtpPromoIdentifier id);
 
+  // Assembles a vector of showable promo objects (ie. the presentation parts
+  // of the promo) to be sent to the NTP.
+  std::vector<NtpShowablePromo> MakeShowablePromos(
+      const std::vector<NtpPromoIdentifier>& ids);
+
   const raw_ref<NtpPromoRegistry> registry_;
   const raw_ref<UserEducationStorageService> storage_service_;
+  std::unique_ptr<NtpPromoOrderPolicy> order_policy_;
 };
 
 }  // namespace user_education
diff --git a/components/user_education/common/ntp_promo/ntp_promo_order.cc b/components/user_education/common/ntp_promo/ntp_promo_order.cc
new file mode 100644
index 0000000..052c083
--- /dev/null
+++ b/components/user_education/common/ntp_promo/ntp_promo_order.cc
@@ -0,0 +1,179 @@
+// 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/user_education/common/ntp_promo/ntp_promo_order.h"
+
+#include <algorithm>
+
+#include "base/containers/contains.h"
+#include "base/logging.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_identifier.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_registry.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_specification.h"
+#include "components/user_education/common/user_education_data.h"
+#include "components/user_education/common/user_education_storage_service.h"
+
+namespace user_education {
+
+namespace {
+
+using ShowAfterMap = std::map<NtpPromoIdentifier, std::set<NtpPromoIdentifier>>;
+
+constexpr int kTopRank = 1;
+
+// Helper to check whether all a promo's show-after dependencies are already
+// satisfied.
+bool DependenciesSatisfied(const NtpPromoIdentifier& id,
+                           const ShowAfterMap& show_after_map,
+                           const std::set<NtpPromoIdentifier>& satisfied) {
+  const auto it = show_after_map.find(id);
+  if (it == show_after_map.end()) {
+    return true;
+  }
+  std::vector<NtpPromoIdentifier> difference;
+  std::set_difference(it->second.begin(), it->second.end(), satisfied.begin(),
+                      satisfied.end(), std::back_inserter(difference));
+  return difference.empty();
+}
+
+// Helper struct to facilitate sorting pending promos.
+struct SortablePendingPromo {
+  NtpPromoIdentifier id;
+  int rank = 0;
+  int last_top_spot_session = 0;
+  int top_spot_session_count = 0;
+};
+
+// Helper struct to facilitate sorting pending promos.
+struct SortableCompletedPromo {
+  NtpPromoIdentifier id;
+  base::Time completed;
+};
+
+}  // namespace
+
+NtpPromoOrderPolicy::NtpPromoOrderPolicy(
+    const NtpPromoRegistry& registry,
+    const UserEducationStorageService& storage_service,
+    int num_sessions_between_rotation)
+    : registry_(registry),
+      storage_service_(storage_service),
+      num_sessions_between_rotation_(num_sessions_between_rotation) {}
+
+NtpPromoOrderPolicy::~NtpPromoOrderPolicy() = default;
+
+std::vector<NtpPromoIdentifier> NtpPromoOrderPolicy::OrderPendingPromos(
+    const std::vector<NtpPromoIdentifier>& ids) {
+  if (ids.size() <= 1) {
+    return ids;
+  }
+
+  // Build a dependency map. This is based on the registry, but excludes
+  // dependencies on promos that aren't in the input list (ie. aren't being
+  // shown for any reason).
+  ShowAfterMap show_after_map;
+  for (const auto& id : ids) {
+    const auto* spec = registry_->GetNtpPromoSpecification(id);
+    CHECK(spec);
+    for (const auto& after : spec->show_after()) {
+      if (base::Contains(ids, after)) {
+        show_after_map[id].insert(after);
+      }
+    }
+  }
+
+  // Construct a sortable list of promo ordering objects.
+  std::vector<SortablePendingPromo> promos;
+  promos.reserve(ids.size());
+  for (const auto& id : ids) {
+    const auto prefs =
+        storage_service_->ReadNtpPromoData(id).value_or(KeyedNtpPromoData());
+    promos.push_back(SortablePendingPromo{
+        .id = id,
+        .last_top_spot_session = prefs.last_top_spot_session,
+        .top_spot_session_count = prefs.top_spot_session_count,
+    });
+  }
+
+  // Group promos into 1-based ranks, according to dependencies. Any promo that
+  // must show after another promo must be ranked with a higher number. Rank 1
+  // is the top rank.
+  std::set<NtpPromoIdentifier> ranked_ids;
+  for (int rank = kTopRank; ranked_ids.size() < ids.size(); rank++) {
+    std::set<NtpPromoIdentifier> newly_ranked_ids;
+    for (auto& promo : promos) {
+      if (!promo.rank &&
+          DependenciesSatisfied(promo.id, show_after_map, ranked_ids)) {
+        promo.rank = rank;
+        newly_ranked_ids.insert(promo.id);
+      }
+    }
+    // If this fails, there's a circular dependency.
+    CHECK(!newly_ranked_ids.empty());
+    ranked_ids.insert(newly_ranked_ids.begin(), newly_ranked_ids.end());
+  }
+
+  // Sort promos by rank, and then by least-recently shown.
+  std::stable_sort(promos.begin(), promos.end(),
+                   [](const SortablePendingPromo& a,
+                      const SortablePendingPromo& b) {
+                     return a.rank < b.rank ||
+                            (a.rank == b.rank &&
+                             a.last_top_spot_session < b.last_top_spot_session);
+                   });
+
+  // If the most-recently-shown top-ranked promo hasn't been shown long enough,
+  // elevate it to the top of the list to be shown again. Essentially, this just
+  // removes that one element and inserts it at the top of the list. In
+  // practice, it uses a C++ container rotation to do that more efficiently than
+  // extracting and inserting at the beginning. Since we're searching from the
+  // bottom, use a reverse iterator to find the last top-ranked promo, and
+  // rotate it to the "end" of the reversed order (ie. the start).
+  auto it_r = std::find_if(
+      promos.rbegin(), promos.rend(),
+      [](const SortablePendingPromo& p) { return (p.rank == kTopRank); });
+  CHECK(it_r != promos.rend());
+  if (it_r->top_spot_session_count > 0 &&
+      it_r->top_spot_session_count < num_sessions_between_rotation_) {
+    std::rotate(it_r, it_r + 1, promos.rend());
+  }
+
+  // Distill and return the ordered list of IDs.
+  std::vector<NtpPromoIdentifier> ordered_ids;
+  ordered_ids.reserve(promos.size());
+  std::transform(promos.begin(), promos.end(), std::back_inserter(ordered_ids),
+                 [](const SortablePendingPromo& promo) { return promo.id; });
+  return ordered_ids;
+}
+
+std::vector<NtpPromoIdentifier> NtpPromoOrderPolicy::OrderCompletedPromos(
+    const std::vector<NtpPromoIdentifier>& ids) {
+  // Construct a sortable list of promo ordering objects.
+  std::vector<SortableCompletedPromo> promos;
+  promos.reserve(ids.size());
+  for (const auto& id : ids) {
+    const auto prefs =
+        storage_service_->ReadNtpPromoData(id).value_or(KeyedNtpPromoData());
+    promos.push_back(SortableCompletedPromo{
+        .id = id,
+        .completed = prefs.completed,
+    });
+  }
+
+  std::stable_sort(
+      promos.begin(), promos.end(),
+      [](const SortableCompletedPromo& a, const SortableCompletedPromo& b) {
+        // Descending time order.
+        return a.completed > b.completed;
+      });
+
+  // Distill and return the ordered list of IDs.
+  std::vector<NtpPromoIdentifier> ordered_ids;
+  ordered_ids.reserve(promos.size());
+  std::transform(promos.begin(), promos.end(), std::back_inserter(ordered_ids),
+                 [](const SortableCompletedPromo& promo) { return promo.id; });
+  return ordered_ids;
+}
+
+}  // namespace user_education
diff --git a/components/user_education/common/ntp_promo/ntp_promo_order.h b/components/user_education/common/ntp_promo/ntp_promo_order.h
new file mode 100644
index 0000000..dd093dc
--- /dev/null
+++ b/components/user_education/common/ntp_promo/ntp_promo_order.h
@@ -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.
+
+#ifndef COMPONENTS_USER_EDUCATION_COMMON_NTP_PROMO_NTP_PROMO_ORDER_H_
+#define COMPONENTS_USER_EDUCATION_COMMON_NTP_PROMO_NTP_PROMO_ORDER_H_
+
+#include <vector>
+
+#include "base/memory/raw_ref.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_identifier.h"
+
+namespace user_education {
+
+class NtpPromoRegistry;
+class UserEducationStorageService;
+
+// This object sorts eligible (showable) promos into a order, from which the
+// New Tab Page can select one or more to show. The implementation manages such
+// things as having a particular promo reside at the top of the list for a
+// particular number of sessions before rotating out of the top spot.
+class NtpPromoOrderPolicy {
+ public:
+  NtpPromoOrderPolicy() = delete;
+  NtpPromoOrderPolicy(const NtpPromoRegistry& registry,
+                      const UserEducationStorageService& storage_service,
+                      int num_sessions_between_rotation);
+
+  ~NtpPromoOrderPolicy();
+  NtpPromoOrderPolicy(const NtpPromoOrderPolicy&) = delete;
+  NtpPromoOrderPolicy& operator=(const NtpPromoOrderPolicy&) = delete;
+
+  // Apply ordering to the supplied pending promo IDs, returning a new,
+  // ordered vector.
+  std::vector<NtpPromoIdentifier> OrderPendingPromos(
+      const std::vector<NtpPromoIdentifier>& ids);
+
+  std::vector<NtpPromoIdentifier> OrderCompletedPromos(
+      const std::vector<NtpPromoIdentifier>& ids);
+
+ private:
+  const raw_ref<const NtpPromoRegistry> registry_;
+  const raw_ref<const UserEducationStorageService> storage_service_;
+
+  // Used to control how long a particular promo stays in the top spot, before
+  // the next promo is rotated into that spot. If 0, no rotation is done.
+  int num_sessions_between_rotation_ = 0;
+};
+
+}  // namespace user_education
+
+#endif  // COMPONENTS_USER_EDUCATION_COMMON_NTP_PROMO_NTP_PROMO_ORDER_H_
diff --git a/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc b/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc
new file mode 100644
index 0000000..a067a8d0
--- /dev/null
+++ b/components/user_education/common/ntp_promo/ntp_promo_order_unittest.cc
@@ -0,0 +1,162 @@
+// 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/user_education/common/ntp_promo/ntp_promo_order.h"
+
+#include <memory>
+
+#include "base/test/gtest_util.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_identifier.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_registry.h"
+#include "components/user_education/common/ntp_promo/ntp_promo_specification.h"
+#include "components/user_education/common/user_education_data.h"
+#include "components/user_education/test/test_user_education_storage_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace user_education {
+
+namespace {
+
+using ::testing::ElementsAre;
+
+constexpr int kNumSessionsBetweenRotation = 3;
+
+class NtpPromoOrderTest : public testing::Test {
+ public:
+  NtpPromoOrderTest() {
+    order_policy_ = std::make_unique<NtpPromoOrderPolicy>(
+        registry_, storage_service_, kNumSessionsBetweenRotation);
+  }
+
+ protected:
+  // Puts the promo in the test registry, and initializes desired pref state.
+  void RegisterPromo(NtpPromoIdentifier id,
+                     base::flat_set<NtpPromoIdentifier> show_after,
+                     int last_top_spot_session,
+                     int top_spot_session_count,
+                     base::Time completed_time) {
+    registry_.AddPromo(NtpPromoSpecification(
+        id, NtpPromoContent("", 0, 0),
+        NtpPromoSpecification::EligibilityCallback(),
+        NtpPromoSpecification::ActionCallback(), std::move(show_after),
+        user_education::Metadata()));
+
+    KeyedNtpPromoData pref;
+    pref.last_top_spot_session = last_top_spot_session;
+    pref.top_spot_session_count = top_spot_session_count;
+    pref.completed = completed_time;
+    storage_service_.SaveNtpPromoData(id, pref);
+  }
+
+  // Generates the list of ordered promos, from everything put in the registry.
+  // Eligible or completed state is ignored, since determining that is not
+  // part of the ordering system.
+  std::vector<NtpPromoIdentifier> Pending() {
+    auto promos = registry_.GetNtpPromoIdentifiers();
+    return order_policy_->OrderPendingPromos(std::move(promos));
+  }
+
+  std::vector<NtpPromoIdentifier> Completed() {
+    auto promos = registry_.GetNtpPromoIdentifiers();
+    return order_policy_->OrderCompletedPromos(std::move(promos));
+  }
+
+ private:
+  NtpPromoRegistry registry_;
+  test::TestUserEducationStorageService storage_service_;
+  std::unique_ptr<NtpPromoOrderPolicy> order_policy_;
+};
+
+}  // namespace
+
+TEST_F(NtpPromoOrderTest, PendingSinglePromo) {
+  RegisterPromo("a", {}, 0, 0, base::Time());
+  EXPECT_THAT(Pending(), ElementsAre("a"));
+}
+
+TEST_F(NtpPromoOrderTest, PendingNoPromo) {
+  EXPECT_THAT(Pending(), testing::IsEmpty());
+}
+
+// The promo registry orders by key; ensure this is preserved.
+TEST_F(NtpPromoOrderTest, PendingStableOrder) {
+  RegisterPromo("c", {}, 0, 0, base::Time());
+  RegisterPromo("b", {}, 0, 0, base::Time());
+  RegisterPromo("a", {}, 0, 0, base::Time());
+  EXPECT_THAT(Pending(), ElementsAre("a", "b", "c"));
+}
+
+TEST_F(NtpPromoOrderTest, PendingCircularDependency) {
+  RegisterPromo("a", {"b"}, 0, 0, base::Time());
+  RegisterPromo("b", {"a"}, 0, 0, base::Time());
+  EXPECT_CHECK_DEATH(Pending());
+}
+
+TEST_F(NtpPromoOrderTest, PendingShowAfter) {
+  RegisterPromo("a", {"b"}, 0, 0, base::Time());
+  RegisterPromo("b", {"c"}, 0, 0, base::Time());
+  RegisterPromo("c", {}, 0, 0, base::Time());
+  EXPECT_THAT(Pending(), ElementsAre("c", "b", "a"));
+}
+
+// Promos that have no dependencies should all be shown above any promos that
+// have dependencies. The no-dependency promos form an effective group at the
+// top of the list, so they need to be kept together.
+TEST_F(NtpPromoOrderTest, PendingShowsAfterAllTopRanked) {
+  RegisterPromo("a", {"b"}, 0, 0, base::Time());
+  RegisterPromo("b", {}, 0, 0, base::Time());
+  RegisterPromo("c", {}, 0, 0, base::Time());
+
+  EXPECT_THAT(Pending(), ElementsAre("b", "c", "a"));
+}
+
+TEST_F(NtpPromoOrderTest, PendingLastTopPromoStaysTop) {
+  ASSERT_GT(kNumSessionsBetweenRotation, 1);
+
+  RegisterPromo("a", {}, 100, 1, base::Time());
+  RegisterPromo("b", {}, 0, 0, base::Time());
+
+  EXPECT_THAT(Pending(), ElementsAre("a", "b"));
+}
+
+TEST_F(NtpPromoOrderTest, PendingLastTopPromoStaysTopLastTime) {
+  RegisterPromo("a", {}, 100, kNumSessionsBetweenRotation - 1, base::Time());
+  RegisterPromo("b", {}, 0, 0, base::Time());
+
+  EXPECT_THAT(Pending(), ElementsAre("a", "b"));
+}
+
+TEST_F(NtpPromoOrderTest, PendingLastTopPromoRotates) {
+  RegisterPromo("a", {}, 100, kNumSessionsBetweenRotation, base::Time());
+  RegisterPromo("b", {}, 0, 0, base::Time());
+
+  EXPECT_THAT(Pending(), ElementsAre("b", "a"));
+}
+
+TEST_F(NtpPromoOrderTest, PendingLastTopPromoRotatesWithDependencies) {
+  RegisterPromo("a", {}, 100, kNumSessionsBetweenRotation, base::Time());
+  RegisterPromo("b", {}, 0, 0, base::Time());
+  RegisterPromo("c", {"a"}, 0, 0, base::Time());
+
+  EXPECT_THAT(Pending(), ElementsAre("b", "a", "c"));
+}
+
+TEST_F(NtpPromoOrderTest, CompletedSinglePromo) {
+  RegisterPromo("a", {}, 0, 0, base::Time());
+
+  EXPECT_THAT(Completed(), ElementsAre("a"));
+}
+
+TEST_F(NtpPromoOrderTest, CompletedPromosShowMostRecentFirst) {
+  RegisterPromo("a", {}, 0, 0, base::Time::FromSecondsSinceUnixEpoch(2));
+  RegisterPromo("b", {}, 0, 0, base::Time::FromSecondsSinceUnixEpoch(3));
+  RegisterPromo("c", {}, 0, 0, base::Time::FromSecondsSinceUnixEpoch(1));
+  EXPECT_THAT(Completed(), ElementsAre("b", "a", "c"));
+}
+
+}  // namespace user_education
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index dcb897f9..1d1f167 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -205,6 +205,7 @@
       "router_off.icon",
       "save_cloud.icon",
       "science.icon",
+      "screen_record.icon",
       "screen_share.icon",
       "screen_share_old.icon",
       "search.icon",
diff --git a/components/vector_icons/screen_record.icon b/components/vector_icons/screen_record.icon
new file mode 100644
index 0000000..ec429e0
--- /dev/null
+++ b/components/vector_icons/screen_record.icon
@@ -0,0 +1,63 @@
+// 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.
+
+CANVAS_DIMENSIONS, 24,
+FILL_RULE_NONZERO,
+MOVE_TO, 3.95f, 17.95f,
+CUBIC_TO, 3.33f, 17.12f, 2.86f, 16.2f, 2.51f, 15.19f,
+CUBIC_TO, 2.17f, 14.18f, 2, 13.12f, 2, 12,
+CUBIC_TO, 2, 10.88f, 2.17f, 9.82f, 2.5f, 8.82f,
+CUBIC_TO, 2.83f, 7.82f, 3.31f, 6.91f, 3.93f, 6.07f,
+LINE_TO, 5.38f, 7.5f,
+CUBIC_TO, 4.94f, 8.13f, 4.61f, 8.83f, 4.36f, 9.59f,
+CUBIC_TO, 4.12f, 10.35f, 4, 11.15f, 4, 12,
+CUBIC_TO, 4, 12.85f, 4.12f, 13.66f, 4.36f, 14.43f,
+CUBIC_TO, 4.61f, 15.19f, 4.94f, 15.89f, 5.38f, 16.52f,
+CLOSE,
+MOVE_TO, 12, 22,
+CUBIC_TO, 10.88f, 22, 9.82f, 21.83f, 8.82f, 21.5f,
+CUBIC_TO, 7.82f, 21.17f, 6.91f, 20.69f, 6.07f, 20.07f,
+LINE_TO, 7.5f, 18.63f,
+CUBIC_TO, 8.13f, 19.06f, 8.83f, 19.39f, 9.59f, 19.64f,
+CUBIC_TO, 10.35f, 19.88f, 11.15f, 20, 12, 20,
+CUBIC_TO, 12.85f, 20, 13.65f, 19.88f, 14.41f, 19.64f,
+CUBIC_TO, 15.17f, 19.39f, 15.87f, 19.06f, 16.5f, 18.63f,
+LINE_TO, 17.93f, 20.07f,
+CUBIC_TO, 17.09f, 20.69f, 16.18f, 21.17f, 15.18f, 21.5f,
+CUBIC_TO, 14.18f, 21.83f, 13.12f, 22, 12, 22,
+CLOSE,
+MOVE_TO, 20.05f, 17.95f,
+LINE_TO, 18.63f, 16.52f,
+CUBIC_TO, 19.06f, 15.89f, 19.39f, 15.19f, 19.64f, 14.43f,
+CUBIC_TO, 19.88f, 13.66f, 20, 12.85f, 20, 12,
+CUBIC_TO, 20, 11.15f, 19.88f, 10.35f, 19.64f, 9.59f,
+CUBIC_TO, 19.39f, 8.83f, 19.06f, 8.13f, 18.63f, 7.5f,
+LINE_TO, 20.07f, 6.07f,
+CUBIC_TO, 20.69f, 6.91f, 21.17f, 7.82f, 21.5f, 8.82f,
+CUBIC_TO, 21.83f, 9.82f, 22, 10.88f, 22, 12,
+CUBIC_TO, 22, 13.12f, 21.83f, 14.18f, 21.49f, 15.19f,
+CUBIC_TO, 21.14f, 16.2f, 20.67f, 17.12f, 20.05f, 17.95f,
+CLOSE,
+MOVE_TO, 7.48f, 5.38f,
+LINE_TO, 6.05f, 3.95f,
+CUBIC_TO, 6.88f, 3.33f, 7.8f, 2.86f, 8.81f, 2.51f,
+CUBIC_TO, 9.82f, 2.17f, 10.88f, 2, 12, 2,
+CUBIC_TO, 13.13f, 2, 14.2f, 2.17f, 15.2f, 2.51f,
+CUBIC_TO, 16.2f, 2.86f, 17.12f, 3.33f, 17.95f, 3.95f,
+LINE_TO, 16.52f, 5.38f,
+CUBIC_TO, 15.89f, 4.94f, 15.19f, 4.61f, 14.43f, 4.36f,
+CUBIC_TO, 13.66f, 4.12f, 12.85f, 4, 12, 4,
+CUBIC_TO, 11.15f, 4, 10.34f, 4.12f, 9.57f, 4.36f,
+CUBIC_TO, 8.81f, 4.61f, 8.11f, 4.94f, 7.48f, 5.38f,
+CLOSE,
+MOVE_TO, 12, 17,
+CUBIC_TO, 10.62f, 17, 9.44f, 16.51f, 8.46f, 15.54f,
+CUBIC_TO, 7.49f, 14.56f, 7, 13.38f, 7, 12,
+CUBIC_TO, 7, 10.62f, 7.49f, 9.44f, 8.46f, 8.46f,
+CUBIC_TO, 9.44f, 7.49f, 10.62f, 7, 12, 7,
+CUBIC_TO, 13.38f, 7, 14.56f, 7.49f, 15.54f, 8.46f,
+CUBIC_TO, 16.51f, 9.44f, 17, 10.62f, 17, 12,
+CUBIC_TO, 17, 13.38f, 16.51f, 14.56f, 15.54f, 15.54f,
+CUBIC_TO, 14.56f, 16.51f, 13.38f, 17, 12, 17,
+CLOSE
diff --git a/components/viz/service/layers/layer_context_impl.cc b/components/viz/service/layers/layer_context_impl.cc
index 7511d03..a00ba6f5 100644
--- a/components/viz/service/layers/layer_context_impl.cc
+++ b/components/viz/service/layers/layer_context_impl.cc
@@ -1718,6 +1718,23 @@
   RETURN_IF_ERROR(CreateOrUpdateLayers(
       *(this->host_impl_.get()), update->layers, update->layer_order, layers));
 
+  // After layers are updated, validate backdrop_mask_element_id.
+  for (const auto& wire : update->effect_nodes) {
+    if (wire->backdrop_mask_element_id) {
+      if (auto* layer =
+              layers.LayerByElementId(wire->backdrop_mask_element_id)) {
+        if (layer->GetLayerType() != cc::mojom::LayerType::kTileDisplay) {
+          return base::unexpected(
+              "Invalid backdrop_mask_element_id: layer is not a "
+              "TileDisplayLayer");
+        }
+      } else {
+        return base::unexpected(
+            "Invalid backdrop_mask_element_id: layer not found");
+      }
+    }
+  }
+
   if (update->local_surface_id_from_parent) {
     layers.SetLocalSurfaceIdFromParent(*update->local_surface_id_from_parent);
     if (update->new_local_surface_id_request) {
diff --git a/components/viz/service/layers/layer_context_impl_property_trees_unittest.cc b/components/viz/service/layers/layer_context_impl_property_trees_unittest.cc
index a7e1205..2993f12 100644
--- a/components/viz/service/layers/layer_context_impl_property_trees_unittest.cc
+++ b/components/viz/service/layers/layer_context_impl_property_trees_unittest.cc
@@ -950,6 +950,75 @@
             "Invalid closest_ancestor_with_shared_element_id for effect node");
 }
 
+TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest,
+       BackdropMaskElementIdValid) {
+  auto update = CreateDefaultUpdate();
+  // Create a TileDisplayLayer to serve as the mask.
+  int mask_layer_id =
+      AddDefaultLayerToUpdate(update.get(), cc::mojom::LayerType::kTileDisplay);
+  cc::ElementId mask_element_id(mask_layer_id);
+  update->layers.back()->element_id = mask_element_id;
+
+  // Create an EffectNode that references this layer.
+  auto node_update = CreateDefaultSecondaryRootEffectNode();
+  node_update->backdrop_mask_element_id = mask_element_id;
+  update->effect_nodes.push_back(std::move(node_update));
+
+  auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update));
+  ASSERT_TRUE(result.has_value());
+
+  cc::EffectNode* node_impl =
+      GetEffectNodeFromActiveTree(cc::kSecondaryRootPropertyNodeId);
+  ASSERT_TRUE(node_impl);
+  EXPECT_EQ(node_impl->backdrop_mask_element_id, mask_element_id);
+}
+
+TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest,
+       BackdropMaskElementIdLayerNotFound) {
+  auto update = CreateDefaultUpdate();
+  cc::ElementId non_existent_element_id(999);
+
+  auto node_update = CreateDefaultSecondaryRootEffectNode();
+  node_update->backdrop_mask_element_id = non_existent_element_id;
+  update->effect_nodes.push_back(std::move(node_update));
+
+  auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update));
+  ASSERT_FALSE(result.has_value());
+  EXPECT_EQ(result.error(),
+            "Invalid backdrop_mask_element_id: layer not found");
+}
+
+TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest,
+       BackdropMaskElementIdNotTileDisplayLayer) {
+  auto update = CreateDefaultUpdate();
+  // Create a regular Layer (not TileDisplayLayer).
+  int mask_layer_id =
+      AddDefaultLayerToUpdate(update.get(), cc::mojom::LayerType::kLayer);
+  cc::ElementId mask_element_id(mask_layer_id);
+  update->layers.back()->element_id = mask_element_id;
+
+  auto node_update = CreateDefaultSecondaryRootEffectNode();
+  node_update->backdrop_mask_element_id = mask_element_id;
+  update->effect_nodes.push_back(std::move(node_update));
+
+  auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update));
+  ASSERT_FALSE(result.has_value());
+  EXPECT_EQ(result.error(),
+            "Invalid backdrop_mask_element_id: layer is not a "
+            "TileDisplayLayer");
+}
+
+TEST_F(LayerContextImplUpdateDisplayTreeEffectNodeTest,
+       BackdropMaskElementIdZeroIsValid) {
+  auto update = CreateDefaultUpdate();
+  auto node_update = CreateDefaultSecondaryRootEffectNode();
+  node_update->backdrop_mask_element_id = cc::ElementId();  // Zero ID
+  update->effect_nodes.push_back(std::move(node_update));
+
+  auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update));
+  ASSERT_TRUE(result.has_value());
+}
+
 class LayerContextImplUpdateDisplayTreeScrollNodeTest
     : public LayerContextImplPropertyTreesTestBase {
  protected:
diff --git a/components/viz/service/layers/layer_context_impl_tiling_unittest.cc b/components/viz/service/layers/layer_context_impl_tiling_unittest.cc
index 6d04b59c..1b43aeb 100644
--- a/components/viz/service/layers/layer_context_impl_tiling_unittest.cc
+++ b/components/viz/service/layers/layer_context_impl_tiling_unittest.cc
@@ -312,5 +312,22 @@
   EXPECT_EQ(result3.error(), "Invalid tile resource");
 }
 
+TEST_F(LayerContextImplUpdateDisplayTilingTest,
+       TilingWithInvalidLayerIdIsIgnored) {
+  constexpr int kInvalidLayerId = 999;  // An ID that doesn't exist.
+
+  auto tiling = CreateTiling(kInvalidLayerId, 1.0f, gfx::Size(64, 64),
+                             gfx::Rect(100, 100));
+  tiling->tiles.push_back(
+      CreateSolidColorTile(cc::TileIndex(0, 0), SkColors::kRed));
+
+  // An update for a non-existent layer should be silently ignored and not
+  // cause a crash or return an error.
+  auto result =
+      layer_context_impl_->DoUpdateDisplayTiling(std::move(tiling),
+                                                 /*update_damage=*/true);
+  EXPECT_TRUE(result.has_value());
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/components/viz/service/layers/layer_context_impl_unittest.cc b/components/viz/service/layers/layer_context_impl_unittest.cc
index 9c2e00a..11bba23a 100644
--- a/components/viz/service/layers/layer_context_impl_unittest.cc
+++ b/components/viz/service/layers/layer_context_impl_unittest.cc
@@ -3932,5 +3932,17 @@
             kDefaultViewTransitionContentLayerMaxExtentsRect);
 }
 
+TEST_F(LayerContextImplTest, UpdateDisplayTreeWithTargetLocalSurfaceId) {
+  auto update = CreateDefaultUpdate();
+  const LocalSurfaceId target_local_surface_id(
+      1, base::UnguessableToken::CreateForTesting(2, 3));
+  update->target_local_surface_id = target_local_surface_id;
+
+  auto result = layer_context_impl_->DoUpdateDisplayTree(std::move(update));
+  EXPECT_TRUE(result.has_value());
+  EXPECT_EQ(layer_context_impl_->host_impl()->target_local_surface_id(),
+            target_local_surface_id);
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/components/webauthn/android/internal_authenticator_android.cc b/components/webauthn/android/internal_authenticator_android.cc
index 7c696eeb..0a30477 100644
--- a/components/webauthn/android/internal_authenticator_android.cc
+++ b/components/webauthn/android/internal_authenticator_android.cc
@@ -77,7 +77,7 @@
 
   std::vector<uint8_t> byte_vector =
       blink::mojom::PaymentOptions::Serialize(&payment);
-  ScopedJavaLocalRef<jobject> byte_buffer = ScopedJavaLocalRef<jobject>(
+  auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size()));
   base::android::CheckException(env);
 
@@ -95,7 +95,7 @@
 
   std::vector<uint8_t> byte_vector =
       blink::mojom::PublicKeyCredentialCreationOptions::Serialize(&options);
-  ScopedJavaLocalRef<jobject> byte_buffer = ScopedJavaLocalRef<jobject>(
+  auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size()));
   base::android::CheckException(env);
 
@@ -113,7 +113,7 @@
 
   std::vector<uint8_t> byte_vector =
       blink::mojom::PublicKeyCredentialRequestOptions::Serialize(&options);
-  ScopedJavaLocalRef<jobject> byte_buffer = ScopedJavaLocalRef<jobject>(
+  auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size()));
   base::android::CheckException(env);
 
diff --git a/components/webauthn/android/webauthn_browser_bridge.cc b/components/webauthn/android/webauthn_browser_bridge.cc
index 77df120..084b978 100644
--- a/components/webauthn/android/webauthn_browser_bridge.cc
+++ b/components/webauthn/android/webauthn_browser_bridge.cc
@@ -67,7 +67,7 @@
   DCHECK_GE(jlength, 0) << "Invalid array length: " << jlength;
   size_t length = static_cast<size_t>(std::max(0, jlength));
   for (size_t i = 0; i < length; ++i) {
-    ScopedJavaLocalRef<jobject> j_credential(
+    auto j_credential = ScopedJavaLocalRef<jobject>::Adopt(
         env, static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
     out->emplace_back(
         ConvertJavaCredentialDetailsToMetadata(env, j_credential));
diff --git a/components/wifi/wifi_service_mac.mm b/components/wifi/wifi_service_mac.mm
index 212f2ff..7123d29 100644
--- a/components/wifi/wifi_service_mac.mm
+++ b/components/wifi/wifi_service_mac.mm
@@ -25,7 +25,7 @@
 #include "base/values.h"
 #include "components/onc/onc_constants.h"
 #include "components/wifi/network_properties.h"
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 
 namespace wifi {
 
@@ -355,7 +355,7 @@
                                       std::string* error) {
   static const char kAirPortServiceName[] = "AirPort";
 
-  auto keychain = crypto::AppleKeychain::DefaultKeychain();
+  auto keychain = crypto::apple::Keychain::DefaultKeychain();
   auto password =
       keychain->FindGenericPassword(kAirPortServiceName, network_guid);
   if (!password.has_value()) {
diff --git a/content/app/mojo/mojo_init.cc b/content/app/mojo/mojo_init.cc
index 34ba8a6..6c00d241 100644
--- a/content/app/mojo/mojo_init.cc
+++ b/content/app/mojo/mojo_init.cc
@@ -7,7 +7,6 @@
 #include <memory>
 
 #include "base/command_line.h"
-#include "base/lazy_instance.h"
 #include "content/public/common/content_switches.h"
 #include "ipc/constants.mojom.h"
 #include "mojo/core/embedder/configuration.h"
@@ -26,12 +25,11 @@
   }
 };
 
-base::LazyInstance<MojoInitializer>::Leaky mojo_initializer;
-
-}  //  namespace
+}  // namespace
 
 void InitializeMojo() {
-  mojo_initializer.Get();
+  // Trivially destructible, so no NoDestructor.
+  static MojoInitializer mojo_initializer;
 }
 
 }  // namespace content
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 4ba3dd25..22a0036 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1929,6 +1929,8 @@
     "renderer_host/navigation_throttle_registry_impl.h",
     "renderer_host/navigation_throttle_runner.cc",
     "renderer_host/navigation_throttle_runner.h",
+    "renderer_host/navigation_throttle_runner2.cc",
+    "renderer_host/navigation_throttle_runner2.h",
     "renderer_host/navigation_transitions/navigation_entry_screenshot.cc",
     "renderer_host/navigation_transitions/navigation_entry_screenshot.h",
     "renderer_host/navigation_transitions/navigation_entry_screenshot_cache.cc",
diff --git a/content/browser/android/content_ui_event_handler.cc b/content/browser/android/content_ui_event_handler.cc
index ddbdf2f..6d8d70f 100644
--- a/content/browser/android/content_ui_event_handler.cc
+++ b/content/browser/android/content_ui_event_handler.cc
@@ -15,6 +15,7 @@
 #include "ui/events/android/key_event_android.h"
 #include "ui/events/android/motion_event_android_factory.h"
 #include "ui/events/android/motion_event_android_java.h"
+#include "ui/events/android/motion_event_android_source_java.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event_utils.h"
 
@@ -88,11 +89,7 @@
 void ContentUiEventHandler::SendMouseWheelEvent(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& motion_event,
-    jlong time_ns,
-    jfloat x,
-    jfloat y,
-    jfloat ticks_x,
-    jfloat ticks_y) {
+    jlong time_ns) {
   auto* event_handler = GetRenderWidgetHostView();
   if (!event_handler)
     return;
@@ -101,8 +98,11 @@
   base::TimeTicks current_time = ui::EventTimeForNow();
   base::TimeTicks event_time = base::TimeTicks::FromJavaNanoTime(time_ns);
   ComputeEventLatencyOS(ui::EventType::kMousewheel, event_time, current_time);
+
+  auto source = ui::MotionEventAndroidSourceJava::Create(motion_event, false);
   ui::MotionEventAndroid::Pointer pointer(
-      /*id=*/0, /*pos_x_pixels=*/x, /*pos_y_pixels=*/y,
+      /*id=*/0, /*pos_x_pixels=*/source->GetXPix(0),
+      /*pos_y_pixels=*/source->GetYPix(0),
       /*touch_major_pixels=*/0.0f,
       /*touch_minor_pixels=*/0.0f, /*pressure=*/0.0f, /*orientation_rad=*/0.0f,
       /*tilt_rad=*/0.0f, /*tool_type=*/0);
@@ -114,7 +114,9 @@
              : ui::kDefaultMouseWheelTickMultiplier * view->GetDipScale();
   auto event = ui::MotionEventAndroidFactory::CreateFromJava(
       env, motion_event,
-      /*pix_to_dip=*/1.f / view->GetDipScale(), ticks_x, ticks_y,
+      /*pix_to_dip=*/1.f / view->GetDipScale(),
+      /*ticks_x=*/source->GetAxisHscroll(0),
+      /*ticks_y=*/source->GetAxisVscroll(0),
       /*tick_multiplier=*/pixels_per_tick,
       /*oldest_event_time=*/base::TimeTicks::FromJavaNanoTime(time_ns),
       /*android_action=*/0,
@@ -136,29 +138,24 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& motion_event,
     jlong time_ns,
-    jint android_action,
-    jfloat x,
-    jfloat y,
-    jint pointer_id,
-    jfloat pressure,
-    jfloat orientation,
-    jfloat tilt,
     jint android_action_button,
-    jint android_button_state,
     jint android_tool_type) {
   auto* event_handler = GetRenderWidgetHostView();
   if (!event_handler)
     return;
 
+  auto source = ui::MotionEventAndroidSourceJava::Create(motion_event, false);
+
   // Construct a motion_event object minimally, only to convert the raw
   // parameters to ui::MotionEvent values. Since we used only the cached values
   // at index=0, it is okay to even pass a null event to the constructor.
   ui::MotionEventAndroid::Pointer pointer(
-      /*id=*/pointer_id, /*pos_x_pixels=*/x, /*pos_y_pixels=*/y,
+      /*id=*/source->GetPointerId(0), /*pos_x_pixels=*/source->GetXPix(0),
+      /*pos_y_pixels=*/source->GetYPix(0),
       /*touch_major_pixels=*/0.0f,
-      /*touch_minor_pixels=*/0.0f, /*pressure=*/pressure,
-      /*orientation_rad=*/orientation,
-      /*tilt_rad=*/tilt, /*tool_type=*/android_tool_type);
+      /*touch_minor_pixels=*/0.0f, /*pressure=*/source->GetPressure(0),
+      /*orientation_rad=*/source->GetRawOrientation(0),
+      /*tilt_rad=*/source->GetRawTilt(0), /*tool_type=*/android_tool_type);
   auto event = ui::MotionEventAndroidFactory::CreateFromJava(
       env, /*event=*/motion_event,
       /*pix_to_dip=*/1.f / web_contents_->GetNativeView()->GetDipScale(),
@@ -166,11 +163,12 @@
       /*ticks_y=*/0.f,
       /*tick_multiplier=*/0.f,
       /*oldest_event_time=*/base::TimeTicks::FromJavaNanoTime(time_ns),
-      android_action,
+      /*android_action=*/source->GetActionMasked(),
       /*pointer_count=*/1,
       /*history_size=*/0,
       /*action_index=*/0, android_action_button,
-      /*android_gesture_classification=*/0, android_button_state,
+      /*android_gesture_classification=*/0,
+      /*android_button_state=*/source->GetButtonState(),
       /*raw_offset_x_pixels=*/0,
       /*raw_offset_y_pixels=*/0,
       /*for_touch_handle=*/false,
diff --git a/content/browser/android/content_ui_event_handler.h b/content/browser/android/content_ui_event_handler.h
index 84c0832..f4633a93 100644
--- a/content/browser/android/content_ui_event_handler.h
+++ b/content/browser/android/content_ui_event_handler.h
@@ -41,23 +41,11 @@
 
   void SendMouseWheelEvent(JNIEnv* env,
                            const base::android::JavaParamRef<jobject>& event,
-                           jlong time_ns,
-                           jfloat x,
-                           jfloat y,
-                           jfloat ticks_x,
-                           jfloat ticks_y);
+                           jlong time_ns);
   void SendMouseEvent(JNIEnv* env,
                       const base::android::JavaParamRef<jobject>& event,
                       jlong time_ns,
-                      jint android_action,
-                      jfloat x,
-                      jfloat y,
-                      jint pointer_id,
-                      jfloat pressure,
-                      jfloat orientation,
-                      jfloat tilt,
                       jint android_action_button,
-                      jint android_button_state,
                       jint android_tool_type);
   void SendScrollEvent(JNIEnv* env,
                        jlong time_ms,
diff --git a/content/browser/android/java/gin_java_method_invocation_helper.cc b/content/browser/android/java/gin_java_method_invocation_helper.cc
index 719faf03..2d0c3dd 100644
--- a/content/browser/android/java/gin_java_method_invocation_helper.cc
+++ b/content/browser/android/java/gin_java_method_invocation_helper.cc
@@ -292,7 +292,8 @@
             mojom::GinJavaBridgeError::kGinJavaBridgeJavaExceptionRaised);
         return;
       }
-      ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string);
+      auto scoped_java_string =
+          ScopedJavaLocalRef<jstring>::Adopt(env, java_string);
       if (!scoped_java_string.obj()) {
         // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined.
         // Spec requires returning a null string.
@@ -316,7 +317,8 @@
             mojom::GinJavaBridgeError::kGinJavaBridgeJavaExceptionRaised);
         return;
       }
-      ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object);
+      auto scoped_java_object =
+          ScopedJavaLocalRef<jobject>::Adopt(env, java_object);
       if (!scoped_java_object.obj()) {
         result_wrapper.Append(base::Value());
         break;
diff --git a/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc b/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
index 914e37b1..391d200 100644
--- a/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
+++ b/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
@@ -173,7 +173,7 @@
         base::android::MethodID::Get<base::android::MethodID::TYPE_INSTANCE>(
             env, clazz.obj(), "hashCode", "()I");
     EXPECT_TRUE(method_id);
-    base::android::ScopedJavaLocalRef<jobject> method_obj(
+    auto method_obj = base::android::ScopedJavaLocalRef<jobject>::Adopt(
         env, env->ToReflectedMethod(clazz.obj(), method_id, false));
     EXPECT_TRUE(method_obj.obj());
     method_ = std::make_unique<JavaMethod>(method_obj);
@@ -239,7 +239,7 @@
   ~MethodNotFoundObjectDelegate() override = default;
 
   base::android::ScopedJavaLocalRef<jobject> GetLocalRef(JNIEnv* env) override {
-    return base::android::ScopedJavaLocalRef<jobject>(
+    return base::android::ScopedJavaLocalRef<jobject>::Adopt(
         env, static_cast<jobject>(env->FindClass("java/lang/String")));
   }
 
diff --git a/content/browser/android/java/java_method.cc b/content/browser/android/java/java_method.cc
index 44056b8f..9a2c453e 100644
--- a/content/browser/android/java/java_method.cc
+++ b/content/browser/android/java/java_method.cc
@@ -101,7 +101,7 @@
   // Form the signature and record the parameter types.
   parameter_types_.resize(num_parameters_);
   for (size_t i = 0; i < num_parameters_; ++i) {
-    ScopedJavaLocalRef<jclass> parameter(
+    auto parameter = ScopedJavaLocalRef<jclass>::Adopt(
         env,
         static_cast<jclass>(env->GetObjectArrayElement(parameters.obj(), i)));
     signature += BinaryNameToJNISignature(GetClassName(env, parameter),
diff --git a/content/browser/android/select_popup.cc b/content/browser/android/select_popup.cc
index 657f2d06..37f460f 100644
--- a/content/browser/android/select_popup.cc
+++ b/content/browser/android/select_popup.cc
@@ -85,18 +85,19 @@
         native_selected_array[selected_count++] = i;
     }
 
-    selected_array =
-        ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(selected_count));
+    selected_array = ScopedJavaLocalRef<jintArray>::Adopt(
+        env, env->NewIntArray(selected_count));
     env->SetIntArrayRegion(selected_array.obj(), 0, selected_count,
                            native_selected_array.data());
   } else {
-    selected_array = ScopedJavaLocalRef<jintArray>(env, env->NewIntArray(1));
+    selected_array =
+        ScopedJavaLocalRef<jintArray>::Adopt(env, env->NewIntArray(1));
     jint value = selected_item;
     env->SetIntArrayRegion(selected_array.obj(), 0, 1, &value);
   }
 
-  ScopedJavaLocalRef<jintArray> enabled_array(env,
-                                              env->NewIntArray(items.size()));
+  auto enabled_array =
+      ScopedJavaLocalRef<jintArray>::Adopt(env, env->NewIntArray(items.size()));
   std::vector<std::string> labels;
   labels.reserve(items.size());
   for (size_t i = 0; i < items.size(); ++i) {
diff --git a/content/browser/bluetooth/bluetooth_blocklist.cc b/content/browser/bluetooth/bluetooth_blocklist.cc
index afb85b7..a65e211 100644
--- a/content/browser/bluetooth/bluetooth_blocklist.cc
+++ b/content/browser/bluetooth/bluetooth_blocklist.cc
@@ -8,6 +8,7 @@
 
 #include "base/check.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "base/strings/string_split.h"
 #include "content/browser/bluetooth/bluetooth_util.h"
 #include "content/public/browser/content_browser_client.h"
@@ -17,20 +18,14 @@
 using device::BluetoothUUID;
 using ManufacturerId = device::BluetoothDevice::ManufacturerId;
 
-namespace {
-
-static base::LazyInstance<content::BluetoothBlocklist>::Leaky g_singleton =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
 namespace content {
 
 BluetoothBlocklist::~BluetoothBlocklist() {}
 
 // static
 BluetoothBlocklist& BluetoothBlocklist::Get() {
-  return g_singleton.Get();
+  static base::NoDestructor<BluetoothBlocklist> singleton;
+  return *singleton;
 }
 
 void BluetoothBlocklist::Add(const BluetoothUUID& uuid, Value value) {
diff --git a/content/browser/bluetooth/bluetooth_blocklist.h b/content/browser/bluetooth/bluetooth_blocklist.h
index a6051fc..68473855 100644
--- a/content/browser/bluetooth/bluetooth_blocklist.h
+++ b/content/browser/bluetooth/bluetooth_blocklist.h
@@ -9,7 +9,7 @@
 #include <string_view>
 #include <vector>
 
-#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
 #include "content/common/content_export.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
@@ -112,8 +112,8 @@
   void ResetToDefaultValuesForTest();
 
  private:
-  // friend LazyInstance to permit access to private constructor.
-  friend base::LazyInstanceTraitsBase<BluetoothBlocklist>;
+  // friend NoDestructor to permit access to private constructor.
+  friend class base::NoDestructor<BluetoothBlocklist>;
 
   BluetoothBlocklist();
 
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index e140a50..1c12257 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -234,7 +234,7 @@
 #include "content/browser/xr/webxr_internals/webxr_internals_ui.h"
 #endif
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
 #include "content/public/browser/service_process_host.h"
 #else
 #include "content/browser/gpu/gpu_process_host.h"
@@ -271,7 +271,7 @@
       mojo::Remote<shape_detection::mojom::ShapeDetectionService>>
       remote;
   if (!*remote) {
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
     ServiceProcessHost::Launch<shape_detection::mojom::ShapeDetectionService>(
         remote->BindNewPipeAndPassReceiver(),
         ServiceProcessHost::Options()
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 8df47374..0601f108 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -11,10 +11,10 @@
 
 #include "base/functional/bind.h"
 #include "base/json/json_reader.h"
-#include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "components/viz/common/buildflags.h"
@@ -94,16 +94,16 @@
 namespace {
 using RenderFrameDevToolsMap =
     std::map<FrameTreeNode*, RenderFrameDevToolsAgentHost*>;
-base::LazyInstance<RenderFrameDevToolsMap>::Leaky g_agent_host_instances =
-    LAZY_INSTANCE_INITIALIZER;
+RenderFrameDevToolsMap& GetAgentHostInstances() {
+  static base::NoDestructor<RenderFrameDevToolsMap> agent_host_instances;
+  return *agent_host_instances;
+}
 
 static bool g_was_ever_attached_to_any_frame = false;
 
 RenderFrameDevToolsAgentHost* FindAgentHost(FrameTreeNode* frame_tree_node) {
-  if (!g_agent_host_instances.IsCreated())
-    return nullptr;
-  auto it = g_agent_host_instances.Get().find(frame_tree_node);
-  return it == g_agent_host_instances.Get().end() ? nullptr : it->second;
+  auto it = GetAgentHostInstances().find(frame_tree_node);
+  return it == GetAgentHostInstances().end() ? nullptr : it->second;
 }
 
 bool ShouldCreateDevToolsForNode(FrameTreeNode* ftn) {
@@ -264,7 +264,7 @@
   }
   RenderProcessHost* rph = rfh->GetProcess();
   std::set<url::Origin> process_origins;
-  for (const auto& entry : g_agent_host_instances.Get()) {
+  for (const auto& entry : GetAgentHostInstances()) {
     RenderFrameHostImpl* frame_host = entry.second->frame_host_;
     if (!frame_host)
       continue;
@@ -307,7 +307,7 @@
 void RenderFrameDevToolsAgentHost::SetFrameTreeNode(
     FrameTreeNode* frame_tree_node) {
   if (frame_tree_node_)
-    g_agent_host_instances.Get().erase(frame_tree_node_);
+    GetAgentHostInstances().erase(frame_tree_node_);
   frame_tree_node_ = frame_tree_node;
   if (frame_tree_node_) {
     DCHECK(web_contents() ==
@@ -316,7 +316,7 @@
     // we may get two agent hosts for the same FrameTreeNode.
     // That is definitely a bug, and we should fix that, and DCHECK
     // here that there is no other agent host.
-    g_agent_host_instances.Get()[frame_tree_node] = this;
+    GetAgentHostInstances()[frame_tree_node] = this;
   }
 }
 
@@ -978,7 +978,7 @@
 
   bool is_same_origin_debugger_attached_in_another_renderer = false;
   bool is_same_origin_debugger_paused_in_another_renderer = false;
-  for (const auto& entry : g_agent_host_instances.Get()) {
+  for (const auto& entry : GetAgentHostInstances()) {
     RenderFrameDevToolsAgentHost* agent_host = entry.second;
     if (agent_host == this || !agent_host->GetWebContents()) {
       continue;
diff --git a/content/browser/devtools/web_contents_devtools_agent_host.cc b/content/browser/devtools/web_contents_devtools_agent_host.cc
index 15e5a7c..09893d8 100644
--- a/content/browser/devtools/web_contents_devtools_agent_host.cc
+++ b/content/browser/devtools/web_contents_devtools_agent_host.cc
@@ -5,6 +5,7 @@
 #include "content/browser/devtools/web_contents_devtools_agent_host.h"
 
 #include "base/memory/raw_ptr.h"
+#include "base/no_destructor.h"
 #include "base/unguessable_token.h"
 #include "content/browser/devtools/protocol/io_handler.h"
 #include "content/browser/devtools/protocol/target_auto_attacher.h"
@@ -20,14 +21,14 @@
 namespace {
 using WebContentsDevToolsMap =
     std::map<WebContents*, WebContentsDevToolsAgentHost*>;
-base::LazyInstance<WebContentsDevToolsMap>::Leaky g_agent_host_instances =
-    LAZY_INSTANCE_INITIALIZER;
+WebContentsDevToolsMap& GetAgentHostInstances() {
+  static base::NoDestructor<WebContentsDevToolsMap> agent_host_instances;
+  return *agent_host_instances;
+}
 
 WebContentsDevToolsAgentHost* FindAgentHost(WebContents* wc) {
-  if (!g_agent_host_instances.IsCreated())
-    return nullptr;
-  auto it = g_agent_host_instances.Get().find(wc);
-  return it == g_agent_host_instances.Get().end() ? nullptr : it->second;
+  auto it = GetAgentHostInstances().find(wc);
+  return it == GetAgentHostInstances().end() ? nullptr : it->second;
 }
 
 }  // namespace
@@ -162,13 +163,13 @@
   // a different host created.
   // TODO(caseq): find a better solution. See also a similar comment in
   // RenderFrameDevToolsAgentHost::SetFrameTreeNode();
-  auto prev_entry = g_agent_host_instances.Get().find(wc);
-  if (prev_entry != g_agent_host_instances.Get().end()) {
+  auto prev_entry = GetAgentHostInstances().find(wc);
+  if (prev_entry != GetAgentHostInstances().end()) {
     CHECK_NE(prev_entry->second, this);
     prev_entry->second->InnerDetach();
   }
   const bool inserted =
-      g_agent_host_instances.Get().insert(std::make_pair(wc, this)).second;
+      GetAgentHostInstances().insert(std::make_pair(wc, this)).second;
   CHECK(inserted);
   auto_attacher_->SetWebContents(wc);
   Observe(wc);
@@ -180,7 +181,7 @@
 void WebContentsDevToolsAgentHost::InnerDetach() {
   DCHECK_EQ(this, FindAgentHost(web_contents()));
   auto_attacher_->SetWebContents(nullptr);
-  g_agent_host_instances.Get().erase(web_contents());
+  GetAgentHostInstances().erase(web_contents());
   Observe(nullptr);
   // We may or may not be destruced here, depending on embedders
   // potentially retaining references.
diff --git a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
index 5616fe18..6fea4be7 100644
--- a/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
+++ b/content/browser/file_system_access/file_path_watcher/file_path_watcher_inotify.cc
@@ -30,12 +30,12 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/no_destructor.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/synchronization/lock.h"
 #include "base/task/sequenced_task_runner.h"
@@ -141,11 +141,11 @@
   bool HasWatches();
 
  private:
-  friend struct base::LazyInstanceTraitsBase<InotifyReader>;
+  friend class base::NoDestructor<InotifyReader>;
 
   InotifyReader();
-  // There is no destructor because |g_inotify_reader| is a
-  // base::LazyInstance::Leaky object. Having a destructor causes build
+  // There is no destructor because |GetInotifyReader()| is a
+  // base::NoDestructor object. Having a destructor causes build
   // issues with GCC 6 (http://crbug.com/636346).
 
   // Returns true on successful thread creation.
@@ -394,8 +394,10 @@
   base::WeakPtrFactory<FilePathWatcherImpl> weak_factory_{this};
 };
 
-base::LazyInstance<InotifyReader>::Leaky g_inotify_reader =
-    LAZY_INSTANCE_INITIALIZER;
+InotifyReader& GetInotifyReader() {
+  static base::NoDestructor<InotifyReader> inotify_reader;
+  return *inotify_reader;
+}
 
 void InotifyReaderThreadDelegate::ThreadMain() {
   base::PlatformThread::SetName("file_system_access_inotify_reader");
@@ -461,14 +463,14 @@
             // Matching IN_MOVED_TO is observed for the existing pending move.
             // Match up the two move events, and reset
             // `pending_move_from_event`.
-            g_inotify_reader.Get().OnInotifyMatchingMoveEvents(
+            GetInotifyReader().OnInotifyMatchingMoveEvents(
                 pending_move_from_event, event);
             pending_move_from_event = nullptr;
             continue;
           }
           // No matching IN_MOVED_TO is observed for `pending_move_from_event`.
           // Flush and reset `pending_move_from_event`.
-          g_inotify_reader.Get().OnInotifyEvent(pending_move_from_event);
+          GetInotifyReader().OnInotifyEvent(pending_move_from_event);
           pending_move_from_event = nullptr;
         }
 
@@ -479,7 +481,7 @@
           pending_move_from_event = event;
         } else {
           // Process other events as normal.
-          g_inotify_reader.Get().OnInotifyEvent(event);
+          GetInotifyReader().OnInotifyEvent(event);
         }
       }
 
@@ -496,7 +498,7 @@
       // If we don't have another batch to process, assume any pending move-from
       // event doesn't have a matching move-to event.
       if (!has_batch && pending_move_from_event) {
-        g_inotify_reader.Get().OnInotifyEvent(pending_move_from_event);
+        GetInotifyReader().OnInotifyEvent(pending_move_from_event);
       }
     }
   }
@@ -517,7 +519,7 @@
 }
 
 bool InotifyReader::StartThread() {
-  // This object is LazyInstance::Leaky, so thread_delegate_ will outlive the
+  // This object is base::NoDestructor, so thread_delegate_ will outlive the
   // thread.
   return base::PlatformThread::CreateNonJoinable(0, &thread_delegate_);
 }
@@ -1041,7 +1043,7 @@
   // We're clearing `watches_` so make sure we're reporting usage changes.
   CHECK(monitoring_usage_changes_);
   for (const auto& watch : watches_) {
-    g_inotify_reader.Get().RemoveWatch(watch.watch, this);
+    GetInotifyReader().RemoveWatch(watch.watch, this);
   }
   watches_.clear();
   target_.clear();
@@ -1062,7 +1064,7 @@
     InotifyReader::Watch old_watch = watch_entry.watch;
     watch_entry.watch = InotifyReader::kInvalidWatch;
     watch_entry.linkname.clear();
-    watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
+    watch_entry.watch = GetInotifyReader().AddWatch(path, this);
     if (watch_entry.watch == InotifyReader::kWatchLimitExceeded) {
       return false;
     }
@@ -1078,7 +1080,7 @@
       }
     }
     if (old_watch != watch_entry.watch) {
-      g_inotify_reader.Get().RemoveWatch(old_watch, this);
+      GetInotifyReader().RemoveWatch(old_watch, this);
     }
     path = path.Append(watch_entry.subdir);
   }
@@ -1134,15 +1136,15 @@
     // a dir with Chrome OS file manager open for the dir). In such case,
     // `cur_dir` under `changed_dir` could exist in this loop but not in
     // the FileEnumerator loop in the upcoming UpdateRecursiveWatchesForPath(),
-    // As a result, `g_inotify_reader` would have an entry in its `watchers_`
+    // As a result, `GetInotifyReader()` would have an entry in its `watchers_`
     // pointing to `this` but `this` is no longer aware of that. Crash in
     // http://crbug/990004 could happen later.
     //
     // Remove the watcher of `cur_path` regardless of whether it exists
-    // or not to keep `this` and `g_inotify_reader` consistent even when the
+    // or not to keep `this` and `GetInotifyReader()` consistent even when the
     // race happens. The watcher will be added back if `cur_path` exists in
     // the FileEnumerator loop in UpdateRecursiveWatchesForPath().
-    g_inotify_reader.Get().RemoveWatch(end_it->second, this);
+    GetInotifyReader().RemoveWatch(end_it->second, this);
 
     // Keep it in sync with |recursive_watches_by_path_| crbug.com/995196.
     recursive_paths_by_watch_.erase(end_it->second);
@@ -1182,8 +1184,7 @@
     // needs to be an add or update operation.
     if (!Contains(recursive_watches_by_path_, current)) {
       // Try to add new watches.
-      InotifyReader::Watch watch =
-          g_inotify_reader.Get().AddWatch(current, this);
+      InotifyReader::Watch watch = GetInotifyReader().AddWatch(current, this);
       if (watch == InotifyReader::kWatchLimitExceeded) {
         return false;
       }
@@ -1200,13 +1201,12 @@
       // Update existing watches.
       InotifyReader::Watch old_watch = recursive_watches_by_path_[current];
       DUMP_WILL_BE_CHECK_NE(InotifyReader::kInvalidWatch, old_watch);
-      InotifyReader::Watch watch =
-          g_inotify_reader.Get().AddWatch(current, this);
+      InotifyReader::Watch watch = GetInotifyReader().AddWatch(current, this);
       if (watch == InotifyReader::kWatchLimitExceeded) {
         return false;
       }
       if (watch != old_watch) {
-        g_inotify_reader.Get().RemoveWatch(old_watch, this);
+        GetInotifyReader().RemoveWatch(old_watch, this);
         recursive_paths_by_watch_.erase(old_watch);
         recursive_watches_by_path_.erase(current);
         TrackWatchForRecursion(watch, current);
@@ -1244,7 +1244,7 @@
   }
 
   for (const auto& it : recursive_paths_by_watch_) {
-    g_inotify_reader.Get().RemoveWatch(it.first, this);
+    GetInotifyReader().RemoveWatch(it.first, this);
   }
 
   recursive_paths_by_watch_.clear();
@@ -1269,7 +1269,7 @@
   // changes to a component "/" which is harmless so no special treatment of
   // this case is required.
   InotifyReader::Watch watch =
-      g_inotify_reader.Get().AddWatch(link->DirName(), this);
+      GetInotifyReader().AddWatch(link->DirName(), this);
   if (watch == InotifyReader::kWatchLimitExceeded) {
     return false;
   }
@@ -1382,7 +1382,7 @@
 
 // static
 bool FilePathWatcher::HasWatchesForTest() {
-  return g_inotify_reader.Get().HasWatches();
+  return GetInotifyReader().HasWatches();
 }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl.cc b/content/browser/file_system_access/file_system_access_directory_handle_impl.cc
index e9956a6..90631a6 100644
--- a/content/browser/file_system_access/file_system_access_directory_handle_impl.cc
+++ b/content/browser/file_system_access/file_system_access_directory_handle_impl.cc
@@ -115,17 +115,17 @@
     default;
 
 void FileSystemAccessDirectoryHandleImpl::GetPermissionStatus(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     GetPermissionStatusCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DoGetPermissionStatus(writable, std::move(callback));
+  DoGetPermissionStatus(mode, std::move(callback));
 }
 
 void FileSystemAccessDirectoryHandleImpl::RequestPermission(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     RequestPermissionCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DoRequestPermission(writable, std::move(callback));
+  DoRequestPermission(mode, std::move(callback));
 }
 
 void FileSystemAccessDirectoryHandleImpl::GetFile(const std::string& basename,
diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl.h b/content/browser/file_system_access/file_system_access_directory_handle_impl.h
index 6907612f..39f71540 100644
--- a/content/browser/file_system_access/file_system_access_directory_handle_impl.h
+++ b/content/browser/file_system_access/file_system_access_directory_handle_impl.h
@@ -45,9 +45,9 @@
   ~FileSystemAccessDirectoryHandleImpl() override;
 
   // blink::mojom::FileSystemAccessDirectoryHandle:
-  void GetPermissionStatus(bool writable,
+  void GetPermissionStatus(blink::mojom::FileSystemAccessPermissionMode mode,
                            GetPermissionStatusCallback callback) override;
-  void RequestPermission(bool writable,
+  void RequestPermission(blink::mojom::FileSystemAccessPermissionMode mode,
                          RequestPermissionCallback callback) override;
   void GetFile(const std::string& basename,
                bool create,
diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc b/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc
index e2af9b0..a9a5b30d 100644
--- a/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/gmock_callback_support.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "build/build_config.h"
@@ -25,6 +26,7 @@
 #include "content/browser/file_system_access/file_system_access_lock_manager.h"
 #include "content/browser/file_system_access/fixed_file_system_access_permission_grant.h"
 #include "content/browser/file_system_access/mock_file_system_access_permission_context.h"
+#include "content/browser/file_system_access/mock_file_system_access_permission_grant.h"
 #include "content/public/browser/file_system_access_permission_context.h"
 #include "content/public/test/browser_task_environment.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
@@ -34,6 +36,7 @@
 #include "storage/common/file_system/file_system_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/storage_key/storage_key.h"
 #include "url/gurl.h"
 
@@ -46,10 +49,25 @@
     FileSystemAccessPermissionContext::SensitiveEntryResult;
 using UserAction = FileSystemAccessPermissionContext::UserAction;
 using LockType = FileSystemAccessLockManager::LockType;
+using blink::mojom::PermissionStatus;
 
-class FileSystemAccessDirectoryHandleImplTest : public testing::Test {
+// A matcher to check if a `RequestPermission()` call is successful and
+// returns the expected permission status.
+MATCHER_P(IsOkAndPermissionStatus, status, "") {
+  if (arg.first->status != blink::mojom::FileSystemAccessStatus::kOk) {
+    *result_listener << "FileSystemAccessStatus is " << arg.first->status;
+    return false;
+  }
+  if (arg.second != status) {
+    *result_listener << "PermissionStatus is " << arg.second;
+    return false;
+  }
+  return true;
+}
+
+class FileSystemAccessDirectoryHandleImplTestBase : public testing::Test {
  public:
-  FileSystemAccessDirectoryHandleImplTest()
+  FileSystemAccessDirectoryHandleImplTestBase()
       : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
 
   void SetUp() override {
@@ -176,6 +194,9 @@
 };
 }  // namespace
 
+class FileSystemAccessDirectoryHandleImplTest
+    : public FileSystemAccessDirectoryHandleImplTestBase {};
+
 TEST_F(FileSystemAccessDirectoryHandleImplTest, GetEntries) {
   constexpr const char* kSafeNames[] = {"a", "a.txt", "My Computer", "lnk.txt",
                                         "a.local"};
@@ -483,4 +504,283 @@
   EXPECT_EQ(file_url.bucket().value(), custom_bucket);
 }
 
+class FileSystemAccessDirectoryHandleImplPermissionTest
+    : public FileSystemAccessDirectoryHandleImplTestBase {
+ public:
+  void SetUp() override {
+    FileSystemAccessDirectoryHandleImplTestBase::SetUp();
+    mock_read_grant_ = base::MakeRefCounted<
+        testing::StrictMock<MockFileSystemAccessPermissionGrant>>();
+    mock_write_grant_ = base::MakeRefCounted<
+        testing::StrictMock<MockFileSystemAccessPermissionGrant>>();
+  }
+
+ protected:
+  // Creates a handle to a directory named "test_dir" in the test directory.
+  std::unique_ptr<FileSystemAccessDirectoryHandleImpl> CreateHandle() {
+    auto test_path = dir_.GetPath().AppendASCII("test_dir");
+    EXPECT_TRUE(base::CreateDirectory(test_path));
+    auto url = manager_->CreateFileSystemURLFromPath(PathInfo(test_path));
+    return std::make_unique<FileSystemAccessDirectoryHandleImpl>(
+        manager_.get(), kFrameBindingContext, url,
+        FileSystemAccessManagerImpl::SharedHandleState(mock_read_grant_,
+                                                       mock_write_grant_));
+  }
+
+  // Calls GetPermissionStatus() on the given `handle` and waits for the result.
+  void GetPermissionStatus(FileSystemAccessDirectoryHandleImpl* handle,
+                           blink::mojom::FileSystemAccessPermissionMode mode,
+                           blink::mojom::PermissionStatus* out_status) {
+    base::test::TestFuture<blink::mojom::PermissionStatus> future;
+    handle->GetPermissionStatus(mode, future.GetCallback());
+    *out_status = future.Get();
+  }
+
+  // Calls RequestPermission() on the given `handle` and waits for the result.
+  std::pair<blink::mojom::FileSystemAccessErrorPtr,
+            blink::mojom::PermissionStatus>
+  RequestPermission(FileSystemAccessDirectoryHandleImpl* handle,
+                    blink::mojom::FileSystemAccessPermissionMode mode) {
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           blink::mojom::PermissionStatus>
+        future;
+    handle->RequestPermission(mode, future.GetCallback());
+    return future.Take();
+  }
+
+  // Sets up expectations for a call to `RequestPermission()` on a mock grant.
+  void SetUpGrantExpectations(
+      testing::StrictMock<MockFileSystemAccessPermissionGrant>& grant,
+      PermissionStatus new_status,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome outcome) {
+    EXPECT_CALL(grant, GetStatus())
+        .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+    EXPECT_CALL(
+        grant,
+        RequestPermission_(
+            kFrameId,
+            FileSystemAccessPermissionGrant::UserActivationState::kRequired, _))
+        .WillOnce(
+            testing::DoAll(testing::InvokeWithoutArgs([&grant, new_status]() {
+                             EXPECT_CALL(grant, GetStatus())
+                                 .WillRepeatedly(testing::Return(new_status));
+                           }),
+                           base::test::RunOnceCallback<2>(outcome)));
+  }
+
+  const int kProcessId = 1;
+  const int kFrameRoutingId = 2;
+  const GlobalRenderFrameHostId kFrameId{kProcessId, kFrameRoutingId};
+  const FileSystemAccessManagerImpl::BindingContext kFrameBindingContext = {
+      test_src_storage_key_, test_src_url_, kFrameId};
+
+  scoped_refptr<testing::StrictMock<MockFileSystemAccessPermissionGrant>>
+      mock_read_grant_;
+  scoped_refptr<testing::StrictMock<MockFileSystemAccessPermissionGrant>>
+      mock_write_grant_;
+};
+
+class FileSystemAccessDirectoryHandleImplGetPermissionStatusTest
+    : public FileSystemAccessDirectoryHandleImplPermissionTest {};
+
+// Test with read-only handle.
+TEST_F(FileSystemAccessDirectoryHandleImplGetPermissionStatusTest, ReadHandle) {
+  auto test_path = dir_.GetPath().AppendASCII("test_dir");
+  ASSERT_TRUE(base::CreateDirectory(test_path));
+
+  auto read_only_handle =
+      GetHandleWithPermissions(test_path, /*read=*/true, /*write=*/false);
+
+  blink::mojom::PermissionStatus status;
+  GetPermissionStatus(read_only_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kRead,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+    GetPermissionStatus(read_only_handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite,
+                        &status);
+    EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+  }
+
+  GetPermissionStatus(read_only_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplGetPermissionStatusTest,
+       WriteHandle) {
+  auto test_path = dir_.GetPath().AppendASCII("test_dir");
+  ASSERT_TRUE(base::CreateDirectory(test_path));
+
+  auto write_handle =
+      GetHandleWithPermissions(test_path, /*read=*/false, /*write=*/true);
+
+  blink::mojom::PermissionStatus status;
+  GetPermissionStatus(write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kRead,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+    GetPermissionStatus(write_handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite,
+                        &status);
+    EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+  }
+
+  GetPermissionStatus(write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplGetPermissionStatusTest,
+       ReadWriteHandle) {
+  auto test_path = dir_.GetPath().AppendASCII("test_dir");
+  ASSERT_TRUE(base::CreateDirectory(test_path));
+
+  auto read_write_handle =
+      GetHandleWithPermissions(test_path, /*read=*/true, /*write=*/true);
+
+  blink::mojom::PermissionStatus status;
+  GetPermissionStatus(read_write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kRead,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+    GetPermissionStatus(read_write_handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite,
+                        &status);
+    EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+  }
+
+  GetPermissionStatus(read_write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+}
+
+class FileSystemAccessDirectoryHandleImplRequestPermissionTest
+    : public FileSystemAccessDirectoryHandleImplPermissionTest {};
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestRead_Granted) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kRead),
+      IsOkAndPermissionStatus(PermissionStatus::GRANTED));
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestRead_Denied) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kRead),
+      IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestReadWrite_Granted) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(RequestPermission(
+                  handle.get(),
+                  blink::mojom::FileSystemAccessPermissionMode::kReadWrite),
+              IsOkAndPermissionStatus(PermissionStatus::GRANTED));
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestReadWrite_ReadDenied) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(RequestPermission(
+                  handle.get(),
+                  blink::mojom::FileSystemAccessPermissionMode::kReadWrite),
+              IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestReadWrite_WriteDenied) {
+  auto handle = CreateHandle();
+
+  EXPECT_CALL(*mock_read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+
+  EXPECT_THAT(RequestPermission(
+                  handle.get(),
+                  blink::mojom::FileSystemAccessPermissionMode::kReadWrite),
+              IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestWrite_Granted) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite),
+      IsOkAndPermissionStatus(PermissionStatus::GRANTED));
+}
+
+TEST_F(FileSystemAccessDirectoryHandleImplRequestPermissionTest,
+       RequestWrite_Denied) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite),
+      IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
 }  // namespace content
diff --git a/content/browser/file_system_access/file_system_access_file_handle_impl.cc b/content/browser/file_system_access/file_system_access_file_handle_impl.cc
index a214d96..c80d04c 100644
--- a/content/browser/file_system_access/file_system_access_file_handle_impl.cc
+++ b/content/browser/file_system_access/file_system_access_file_handle_impl.cc
@@ -150,15 +150,15 @@
 FileSystemAccessFileHandleImpl::~FileSystemAccessFileHandleImpl() = default;
 
 void FileSystemAccessFileHandleImpl::GetPermissionStatus(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     GetPermissionStatusCallback callback) {
-  DoGetPermissionStatus(writable, std::move(callback));
+  DoGetPermissionStatus(mode, std::move(callback));
 }
 
 void FileSystemAccessFileHandleImpl::RequestPermission(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     RequestPermissionCallback callback) {
-  DoRequestPermission(writable, std::move(callback));
+  DoRequestPermission(mode, std::move(callback));
 }
 
 void FileSystemAccessFileHandleImpl::AsBlob(AsBlobCallback callback) {
diff --git a/content/browser/file_system_access/file_system_access_file_handle_impl.h b/content/browser/file_system_access/file_system_access_file_handle_impl.h
index 5f730fc..fa78049 100644
--- a/content/browser/file_system_access/file_system_access_file_handle_impl.h
+++ b/content/browser/file_system_access/file_system_access_file_handle_impl.h
@@ -45,9 +45,9 @@
   ~FileSystemAccessFileHandleImpl() override;
 
   // blink::mojom::FileSystemAccessFileHandle:
-  void GetPermissionStatus(bool writable,
+  void GetPermissionStatus(blink::mojom::FileSystemAccessPermissionMode mode,
                            GetPermissionStatusCallback callback) override;
-  void RequestPermission(bool writable,
+  void RequestPermission(blink::mojom::FileSystemAccessPermissionMode mode,
                          RequestPermissionCallback callback) override;
   void AsBlob(AsBlobCallback callback) override;
   void CreateFileWriter(
diff --git a/content/browser/file_system_access/file_system_access_file_handle_impl_unittest.cc b/content/browser/file_system_access/file_system_access_file_handle_impl_unittest.cc
index 174140ca..221fa2f 100644
--- a/content/browser/file_system_access/file_system_access_file_handle_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_file_handle_impl_unittest.cc
@@ -68,6 +68,22 @@
 
 using blink::mojom::PermissionStatus;
 using storage::FileSystemURL;
+using testing::_;
+using testing::FieldsAre;
+
+// A matcher to check if a `RequestPermission()` call is successful and
+// returns the expected permission status.
+MATCHER_P(IsOkAndPermissionStatus, status, "") {
+  if (arg.first->status != blink::mojom::FileSystemAccessStatus::kOk) {
+    *result_listener << "FileSystemAccessStatus is " << arg.first->status;
+    return false;
+  }
+  if (arg.second != status) {
+    *result_listener << "PermissionStatus is " << arg.second;
+    return false;
+  }
+  return true;
+}
 
 // Test fixture for FileSystemAccessFileHandleImpl.
 //
@@ -76,9 +92,9 @@
 //
 // Tests with mock permission context are in
 // FileSystemAccessFileHandleImplMovePermissionsTest.
-class FileSystemAccessFileHandleImplTest : public testing::Test {
+class FileSystemAccessFileHandleImplTestBase : public testing::Test {
  public:
-  FileSystemAccessFileHandleImplTest() = default;
+  FileSystemAccessFileHandleImplTestBase() = default;
 
   void SetUp() override {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
@@ -278,7 +294,7 @@
 };
 
 class FileSystemAccessAccessHandleTest
-    : public FileSystemAccessFileHandleImplTest {
+    : public FileSystemAccessFileHandleImplTestBase {
  public:
   void SetUp() override {
     // AccessHandles are only allowed for temporary file systems.
@@ -329,6 +345,9 @@
 };
 #endif
 
+class FileSystemAccessFileHandleImplTest
+    : public FileSystemAccessFileHandleImplTestBase {};
+
 TEST_F(FileSystemAccessFileHandleImplTest, CreateFileWriterOverLimitNotOK) {
   int max_files = 5;
   handle_->set_max_swap_files_for_testing(max_files);
@@ -866,7 +885,7 @@
 // platform support for copy-on-write files) behaves as expected. Swap file
 // cloning requires storage::kFileSystemTypeLocal.
 class FileSystemAccessFileHandleSwapFileCloningTest
-    : public FileSystemAccessFileHandleImplTest {
+    : public FileSystemAccessFileHandleImplTestBase {
  public:
   enum class CloneFileResult {
     kDidNotAttempt,
@@ -1013,7 +1032,7 @@
 // without access to the destination directory. These tests always grant write
 // access to the destination directory.
 class FileSystemAccessFileHandleImplMovePermissionsTest
-    : public FileSystemAccessFileHandleImplTest,
+    : public FileSystemAccessFileHandleImplTestBase,
       public testing::WithParamInterface<MovePermissionsTestCase> {
  public:
   void SetUp() override {
@@ -1391,7 +1410,7 @@
 }
 
 TEST_P(FileSystemAccessFileHandleImplMovePermissionsTest, Move_SameFile) {
-  auto [source, _] = CreateSourceAndMaybeTarget();
+  auto [source, unused] = CreateSourceAndMaybeTarget();
 
   ExpectFileMoveSuccess(source, source);
 }
@@ -1418,4 +1437,280 @@
       FileSystemAccessPermissionContext::SensitiveEntryResult::kAbort);
 }
 
+class FileSystemAccessFileHandleImplPermissionTest
+    : public FileSystemAccessFileHandleImplTestBase {
+ public:
+  void SetUp() override {
+    FileSystemAccessFileHandleImplTestBase::SetUp();
+    mock_read_grant_ = base::MakeRefCounted<
+        testing::StrictMock<MockFileSystemAccessPermissionGrant>>();
+    mock_write_grant_ = base::MakeRefCounted<
+        testing::StrictMock<MockFileSystemAccessPermissionGrant>>();
+  }
+
+ protected:
+  // Creates a handle to a file named "test_file" in the test directory.
+  std::unique_ptr<FileSystemAccessFileHandleImpl> CreateHandle() {
+    auto test_path = dir_.GetPath().AppendASCII("test_file");
+    EXPECT_TRUE(base::WriteFile(test_path, ""));
+    auto url = manager_->CreateFileSystemURLFromPath(PathInfo(test_path));
+    return std::make_unique<FileSystemAccessFileHandleImpl>(
+        manager_.get(), kFrameBindingContext, url, "test_file",
+        FileSystemAccessManagerImpl::SharedHandleState(mock_read_grant_,
+                                                       mock_write_grant_));
+  }
+
+  // Calls GetPermissionStatus() on the given `handle` and waits for the result.
+  void GetPermissionStatus(FileSystemAccessFileHandleImpl* handle,
+                           blink::mojom::FileSystemAccessPermissionMode mode,
+                           blink::mojom::PermissionStatus* out_status) {
+    base::test::TestFuture<blink::mojom::PermissionStatus> future;
+    handle->GetPermissionStatus(mode, future.GetCallback());
+    *out_status = future.Get();
+  }
+
+  // Calls RequestPermission() on the given `handle` and waits for the result.
+  std::pair<blink::mojom::FileSystemAccessErrorPtr,
+            blink::mojom::PermissionStatus>
+  RequestPermission(FileSystemAccessFileHandleImpl* handle,
+                    blink::mojom::FileSystemAccessPermissionMode mode) {
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           blink::mojom::PermissionStatus>
+        future;
+    handle->RequestPermission(mode, future.GetCallback());
+    return future.Take();
+  }
+
+  // Sets up expectations for a call to `RequestPermission()` on a mock grant.
+  void SetUpGrantExpectations(
+      testing::StrictMock<MockFileSystemAccessPermissionGrant>& grant,
+      PermissionStatus new_status,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome outcome) {
+    EXPECT_CALL(grant, GetStatus())
+        .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+    EXPECT_CALL(
+        grant,
+        RequestPermission_(
+            kFrameId,
+            FileSystemAccessPermissionGrant::UserActivationState::kRequired, _))
+        .WillOnce(
+            testing::DoAll(testing::InvokeWithoutArgs([&grant, new_status]() {
+                             EXPECT_CALL(grant, GetStatus())
+                                 .WillRepeatedly(testing::Return(new_status));
+                           }),
+                           base::test::RunOnceCallback<2>(outcome)));
+  }
+
+  const int kProcessId = 1;
+  const int kFrameRoutingId = 2;
+  const GlobalRenderFrameHostId kFrameId{kProcessId, kFrameRoutingId};
+  const FileSystemAccessManagerImpl::BindingContext kFrameBindingContext = {
+      test_src_storage_key_, test_src_url_, kFrameId};
+
+  scoped_refptr<testing::StrictMock<MockFileSystemAccessPermissionGrant>>
+      mock_read_grant_;
+  scoped_refptr<testing::StrictMock<MockFileSystemAccessPermissionGrant>>
+      mock_write_grant_;
+};
+
+class FileSystemAccessFileHandleImplGetPermissionStatusTest
+    : public FileSystemAccessFileHandleImplPermissionTest {};
+
+TEST_F(FileSystemAccessFileHandleImplGetPermissionStatusTest, ReadHandle) {
+  auto test_path = dir_.GetPath().AppendASCII("test_file");
+  ASSERT_TRUE(base::WriteFile(test_path, ""));
+
+  auto read_only_handle =
+      GetHandleWithPermissions(test_path, allow_grant_, deny_grant_);
+
+  blink::mojom::PermissionStatus status;
+  GetPermissionStatus(read_only_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kRead,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+    GetPermissionStatus(read_only_handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite,
+                        &status);
+    EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+  }
+
+  GetPermissionStatus(read_only_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+}
+
+TEST_F(FileSystemAccessFileHandleImplGetPermissionStatusTest, WriteHandle) {
+  auto test_path = dir_.GetPath().AppendASCII("test_file");
+  ASSERT_TRUE(base::WriteFile(test_path, ""));
+
+  auto write_handle =
+      GetHandleWithPermissions(test_path, deny_grant_, allow_grant_);
+
+  blink::mojom::PermissionStatus status;
+  GetPermissionStatus(write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kRead,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+    GetPermissionStatus(write_handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite,
+                        &status);
+    EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+  }
+
+  GetPermissionStatus(write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
+}
+
+TEST_F(FileSystemAccessFileHandleImplGetPermissionStatusTest, ReadWriteHandle) {
+  auto test_path = dir_.GetPath().AppendASCII("test_file");
+  ASSERT_TRUE(base::WriteFile(test_path, ""));
+
+  auto read_write_handle =
+      GetHandleWithPermissions(test_path, allow_grant_, allow_grant_);
+
+  blink::mojom::PermissionStatus status;
+  GetPermissionStatus(read_write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kRead,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+    GetPermissionStatus(read_write_handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite,
+                        &status);
+    EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+  }
+
+  GetPermissionStatus(read_write_handle.get(),
+                      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                      &status);
+  EXPECT_EQ(status, blink::mojom::PermissionStatus::GRANTED);
+}
+
+class FileSystemAccessFileHandleImplRequestPermissionTest
+    : public FileSystemAccessFileHandleImplPermissionTest {};
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestRead_Granted) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kRead),
+      IsOkAndPermissionStatus(PermissionStatus::GRANTED));
+}
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestRead_Denied) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kRead),
+      IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestReadWrite_Granted) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(RequestPermission(
+                  handle.get(),
+                  blink::mojom::FileSystemAccessPermissionMode::kReadWrite),
+              IsOkAndPermissionStatus(PermissionStatus::GRANTED));
+}
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestReadWrite_ReadDenied) {
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_read_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(RequestPermission(
+                  handle.get(),
+                  blink::mojom::FileSystemAccessPermissionMode::kReadWrite),
+              IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestReadWrite_WriteDenied) {
+  auto handle = CreateHandle();
+
+  EXPECT_CALL(*mock_read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+
+  EXPECT_THAT(RequestPermission(
+                  handle.get(),
+                  blink::mojom::FileSystemAccessPermissionMode::kReadWrite),
+              IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestWrite_Granted) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::GRANTED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserGranted);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite),
+      IsOkAndPermissionStatus(PermissionStatus::GRANTED));
+}
+
+TEST_F(FileSystemAccessFileHandleImplRequestPermissionTest,
+       RequestWrite_Denied) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle();
+
+  SetUpGrantExpectations(
+      *mock_write_grant_, PermissionStatus::DENIED,
+      FileSystemAccessPermissionGrant::PermissionRequestOutcome::kUserDenied);
+
+  EXPECT_THAT(
+      RequestPermission(handle.get(),
+                        blink::mojom::FileSystemAccessPermissionMode::kWrite),
+      IsOkAndPermissionStatus(PermissionStatus::DENIED));
+}
+
 }  // namespace content
diff --git a/content/browser/file_system_access/file_system_access_handle_base.cc b/content/browser/file_system_access/file_system_access_handle_base.cc
index 429e75b..0d7f2be 100644
--- a/content/browser/file_system_access/file_system_access_handle_base.cc
+++ b/content/browser/file_system_access/file_system_access_handle_base.cc
@@ -116,23 +116,29 @@
   return handle_state_.write_grant->GetStatus();
 }
 
+// TODO(crbug.com/40276567): Update callers if they only need write permission.
 void FileSystemAccessHandleBase::DoGetPermissionStatus(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(PermissionStatus)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // TODO(crbug.com/40276567): Update if this only needs write-only permission
-  std::move(callback).Run(writable ? GetReadWritePermissionStatus()
-                                   : GetReadPermissionStatus());
+  std::move(callback).Run(GetPermissionStatusForMode(mode));
 }
 
+// TODO(crbug.com/40276567): Update callers if they only need write permission.
 void FileSystemAccessHandleBase::DoRequestPermission(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(blink::mojom::FileSystemAccessErrorPtr,
                             PermissionStatus)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // TODO(crbug.com/40276567): Update if this only needs write-only permission
-  PermissionStatus current_status =
-      writable ? GetReadWritePermissionStatus() : GetReadPermissionStatus();
+  if (!base::FeatureList::IsEnabled(
+          blink::features::kFileSystemAccessWriteMode) &&
+      mode == blink::mojom::FileSystemAccessPermissionMode::kWrite) {
+    // Rejects invalid mode at the very beginning.
+    mojo::ReportBadMessage("feature 'FileSystemAccessWriteMode' not enabled");
+    NOTREACHED();
+  }
+
+  PermissionStatus current_status = GetPermissionStatusForMode(mode);
   // If we already have a valid permission status, just return that. Also just
   // return the current permission status if this is called from a worker, as we
   // don't support prompting for increased permissions from workers.
@@ -145,16 +151,28 @@
     std::move(callback).Run(file_system_access_error::Ok(), current_status);
     return;
   }
-  if (!writable) {
+
+  // 1. Request "read"-only permission.
+  if (mode == blink::mojom::FileSystemAccessPermissionMode::kRead) {
     handle_state_.read_grant->RequestPermission(
         context().frame_id,
         FileSystemAccessPermissionGrant::UserActivationState::kRequired,
         base::BindOnce(&FileSystemAccessHandleBase::DidRequestPermission,
-                       AsWeakPtr(), writable, std::move(callback)));
+                       AsWeakPtr(), mode, std::move(callback)));
     return;
   }
 
-  // Ask for both read and write permission at the same time, the permission
+  // 2. Request "write"-only permission.
+  if (mode == blink::mojom::FileSystemAccessPermissionMode::kWrite) {
+    handle_state_.write_grant->RequestPermission(
+        context().frame_id,
+        FileSystemAccessPermissionGrant::UserActivationState::kRequired,
+        base::BindOnce(&FileSystemAccessHandleBase::DidRequestPermission,
+                       AsWeakPtr(), mode, std::move(callback)));
+    return;
+  }
+
+  // 3. Ask for both read and write permission at the same time, the permission
   // context should coalesce these into one prompt.
   if (GetReadPermissionStatus() == PermissionStatus::ASK) {
     // Ignore callback for the read permission request; if the request fails,
@@ -171,11 +189,11 @@
       context().frame_id,
       FileSystemAccessPermissionGrant::UserActivationState::kRequired,
       base::BindOnce(&FileSystemAccessHandleBase::DidRequestPermission,
-                     AsWeakPtr(), writable, std::move(callback)));
+                     AsWeakPtr(), mode, std::move(callback)));
 }
 
 void FileSystemAccessHandleBase::DidRequestPermission(
-    bool writable,
+    blink::mojom::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(blink::mojom::FileSystemAccessErrorPtr,
                             PermissionStatus)> callback,
     FileSystemAccessPermissionGrant::PermissionRequestOutcome outcome) {
@@ -188,20 +206,14 @@
           file_system_access_error::FromStatus(
               blink::mojom::FileSystemAccessStatus::kSecurityError,
               "Not allowed to request permissions in this context."),
-          // TODO(crbug.com/40276567): Update if this only needs write-only
-          // permission
-          writable ? GetReadWritePermissionStatus()
-                   : GetReadPermissionStatus());
+          GetPermissionStatusForMode(mode));
       return;
     case Outcome::kNoUserActivation:
       std::move(callback).Run(
           file_system_access_error::FromStatus(
               blink::mojom::FileSystemAccessStatus::kSecurityError,
               "User activation is required to request permissions."),
-          // TODO(crbug.com/40276567): Update if this only needs write-only
-          // permission
-          writable ? GetReadWritePermissionStatus()
-                   : GetReadPermissionStatus());
+          GetPermissionStatusForMode(mode));
       return;
     case Outcome::kBlockedByContentSetting:
     case Outcome::kUserGranted:
@@ -213,10 +225,7 @@
     case Outcome::kGrantedByAncestorPersistentPermission:
     case Outcome::kGrantedByRestorePrompt:
       std::move(callback).Run(file_system_access_error::Ok(),
-                              // TODO(crbug.com/40276567): Update if this only
-                              // needs write-only permission
-                              writable ? GetReadWritePermissionStatus()
-                                       : GetReadPermissionStatus());
+                              GetPermissionStatusForMode(mode));
       return;
   }
   NOTREACHED();
@@ -658,4 +667,17 @@
   return parent;
 }
 
+FileSystemAccessHandleBase::PermissionStatus
+FileSystemAccessHandleBase::GetPermissionStatusForMode(
+    blink::mojom::FileSystemAccessPermissionMode mode) {
+  switch (mode) {
+    case blink::mojom::FileSystemAccessPermissionMode::kRead:
+      return GetReadPermissionStatus();
+    case blink::mojom::FileSystemAccessPermissionMode::kReadWrite:
+      return GetReadWritePermissionStatus();
+    case blink::mojom::FileSystemAccessPermissionMode::kWrite:
+      return GetWritePermissionStatus();
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/file_system_access/file_system_access_handle_base.h b/content/browser/file_system_access/file_system_access_handle_base.h
index 99b0896..3a7ebbdd 100644
--- a/content/browser/file_system_access/file_system_access_handle_base.h
+++ b/content/browser/file_system_access/file_system_access_handle_base.h
@@ -18,6 +18,7 @@
 #include "storage/browser/file_system/file_system_url.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_cloud_identifier.mojom.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
 
 namespace storage {
@@ -76,12 +77,12 @@
   // Implementation for the GetPermissionStatus method in the
   // blink::mojom::FileSystemAccessFileHandle and DirectoryHandle interfaces.
   void DoGetPermissionStatus(
-      bool writable,
+      blink::mojom::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(PermissionStatus)> callback);
   // Implementation for the RequestPermission method in the
   // blink::mojom::FileSystemAccessFileHandle and DirectoryHandle interfaces.
   void DoRequestPermission(
-      bool writable,
+      blink::mojom::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(blink::mojom::FileSystemAccessErrorPtr,
                               PermissionStatus)> callback);
 
@@ -137,7 +138,7 @@
  private:
   storage::FileSystemURL GetParentURL();
   void DidRequestPermission(
-      bool writable,
+      blink::mojom::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(blink::mojom::FileSystemAccessErrorPtr,
                               PermissionStatus)> callback,
       FileSystemAccessPermissionGrant::PermissionRequestOutcome outcome);
@@ -195,6 +196,9 @@
            url.type() != storage::kFileSystemTypeTest;
   }
 
+  PermissionStatus GetPermissionStatusForMode(
+      blink::mojom::FileSystemAccessPermissionMode mode);
+
   // The FileSystemAccessManagerImpl that owns this instance.
   const raw_ptr<FileSystemAccessManagerImpl, DanglingUntriaged> manager_ =
       nullptr;
@@ -213,7 +217,8 @@
     CallbackArgType callback_arg) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DoRequestPermission(
-      /*writable=*/true,
+      // TODO(crbug.com/40276567): Update to "write"-only after spec discussion.
+      blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
       base::BindOnce(
           [](base::OnceCallback<void(CallbackArgType)> callback,
              base::OnceCallback<void(blink::mojom::FileSystemAccessErrorPtr,
diff --git a/content/browser/file_system_access/file_system_access_handle_base_unittest.cc b/content/browser/file_system_access/file_system_access_handle_base_unittest.cc
index 42e1043b..0f205c5 100644
--- a/content/browser/file_system_access/file_system_access_handle_base_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_handle_base_unittest.cc
@@ -251,24 +251,134 @@
   // using `future`.
   void DoRequestPermission(
       TestFileSystemAccessHandle& handle,
-      bool writable,
+      blink::mojom::FileSystemAccessPermissionMode mode,
       base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                              PermissionStatus>& future) {
-    handle.DoRequestPermission(writable, future.GetCallback());
+    handle.DoRequestPermission(mode, future.GetCallback());
   }
 };
 
-class FileSystemAccessDoRequestPermissionTest
+class FileSystemAccessDoRequestReadPermissionTest
     : public FileSystemAccessDoRequestPermissionTestBase,
       public testing::WithParamInterface<TestContextParam> {
  public:
   bool is_worker() const override { return GetParam().is_worker; }
 };
 
-// Tests that `DoRequestPermission` returns `GRANTED` if write permission is
-// requested and both read and write permissions are already `GRANTED`.
-TEST_P(FileSystemAccessDoRequestPermissionTest,
-       RequestReadWritePermission_WritePermissionAlreadyGranted) {
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    FileSystemAccessDoRequestReadPermissionTest,
+    testing::ValuesIn(kTestContextParams),
+    [](const testing::TestParamInfo<TestContextParam>& info) {
+      return info.param.test_name;
+    });
+
+// Tests that `DoRequestPermission` returns `GRANTED` if write permission is not
+// requested and read permission is already `GRANTED`.
+TEST_P(FileSystemAccessDoRequestReadPermissionTest, WritePermissionNotNeeded) {
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*read_grant_, GetStatus())
+      .WillOnce(testing::Return(PermissionStatus::GRANTED));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kRead, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::GRANTED);
+}
+
+// Tests that `DoRequestPermission` returns `DENIED` if read permission is
+// denied when requesting read permission.
+TEST_P(FileSystemAccessDoRequestReadPermissionTest, Denied) {
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+
+  if (is_worker()) {
+    // Workers can't show a permission prompt, so the permission status is
+    // expected to remain ASK.
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           PermissionStatus>
+        future;
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kRead, future);
+    EXPECT_EQ(future.Get<0>()->status,
+              blink::mojom::FileSystemAccessStatus::kOk);
+    EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
+    return;
+  }
+
+  EXPECT_CALL(
+      *read_grant_,
+      RequestPermission_(kFrameId, UserActivationState::kRequired, testing::_))
+      .WillOnce(testing::DoAll(
+          testing::InvokeWithoutArgs([&]() {
+            EXPECT_CALL(*read_grant_, GetStatus())
+                .WillOnce(testing::Return(PermissionStatus::DENIED));
+          }),
+          RunOnceCallback<2>(FileSystemAccessPermissionGrant::
+                                 PermissionRequestOutcome::kUserDenied)));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kRead, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
+}
+
+// Tests that `DoRequestPermission` returns `DENIED` if read permission is
+// already denied when requesting read permission.
+TEST_P(FileSystemAccessDoRequestReadPermissionTest, AlreadyDenied) {
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::DENIED));
+
+  // No permission requests should be made.
+  EXPECT_CALL(*read_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+  EXPECT_CALL(*write_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kRead, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
+}
+
+class FileSystemAccessDoRequestReadWritePermissionTest
+    : public FileSystemAccessDoRequestPermissionTestBase,
+      public testing::WithParamInterface<TestContextParam> {
+ public:
+  bool is_worker() const override { return GetParam().is_worker; }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    FileSystemAccessDoRequestReadWritePermissionTest,
+    testing::ValuesIn(kTestContextParams),
+    [](const testing::TestParamInfo<TestContextParam>& info) {
+      return info.param.test_name;
+    });
+
+// Tests that `DoRequestPermission` requests both read and write permissions
+// when both are already `GRANTED`.
+TEST_P(FileSystemAccessDoRequestReadWritePermissionTest,
+       BothAreAlreadyGranted) {
   auto handle = CreateHandle(kTestStorageKey, kTestURL,
                              base::FilePath::FromUTF8Unsafe("/test"));
 
@@ -280,15 +390,15 @@
   base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                          PermissionStatus>
       future;
-  DoRequestPermission(handle, /*writable=*/true, future);
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
   EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
   EXPECT_EQ(future.Get<1>(), PermissionStatus::GRANTED);
 }
 
 // Tests that `DoRequestPermission` requests both read and write permissions
 // when neither are `GRANTED`.
-TEST_P(FileSystemAccessDoRequestPermissionTest,
-       RequestReadWritePermission_BothAreNotGranted) {
+TEST_P(FileSystemAccessDoRequestReadWritePermissionTest, BothAreNotGranted) {
   auto handle = CreateHandle(kTestStorageKey, kTestURL,
                              base::FilePath::FromUTF8Unsafe("/test"));
 
@@ -303,7 +413,9 @@
     base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                            PermissionStatus>
         future;
-    DoRequestPermission(handle, /*writable=*/true, future);
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+        future);
     EXPECT_EQ(future.Get<0>()->status,
               blink::mojom::FileSystemAccessStatus::kOk);
     EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
@@ -335,15 +447,68 @@
   base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                          PermissionStatus>
       future;
-  DoRequestPermission(handle, /*writable=*/true, future);
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
   EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
   EXPECT_EQ(future.Get<1>(), PermissionStatus::GRANTED);
 }
 
-// Tests that `DoRequestPermission` requests both read and write permissions
-// when both are already `GRANTED`.
-TEST_P(FileSystemAccessDoRequestPermissionTest,
-       RequestReadWritePermission_BothAlreadyGranted) {
+// Tests that `DoRequestPermission` returns `DENIED` if read permission is
+// denied when requesting read & write permission.
+TEST_P(FileSystemAccessDoRequestReadWritePermissionTest, ReadDenied) {
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+  EXPECT_CALL(*write_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+
+  if (is_worker()) {
+    // Workers can't show a permission prompt, so the permission status is
+    // expected to remain ASK.
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           PermissionStatus>
+        future;
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+        future);
+    EXPECT_EQ(future.Get<0>()->status,
+              blink::mojom::FileSystemAccessStatus::kOk);
+    EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
+    return;
+  }
+
+  EXPECT_CALL(
+      *read_grant_,
+      RequestPermission_(kFrameId, UserActivationState::kRequired, testing::_))
+      .WillOnce(testing::DoAll(
+          testing::InvokeWithoutArgs([&]() {
+            EXPECT_CALL(*read_grant_, GetStatus())
+                .WillOnce(testing::Return(PermissionStatus::DENIED));
+          }),
+          RunOnceCallback<2>(FileSystemAccessPermissionGrant::
+                                 PermissionRequestOutcome::kUserDenied)));
+
+  // The implementation may request both permissions.
+  EXPECT_CALL(
+      *write_grant_,
+      RequestPermission_(kFrameId, UserActivationState::kRequired, testing::_))
+      .WillOnce(RunOnceCallback<2>(FileSystemAccessPermissionGrant::
+                                       PermissionRequestOutcome::kUserGranted));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
+}
+
+// Tests that `DoRequestPermission` returns `DENIED` if write permission is
+// denied when requesting read & write permission.
+TEST_P(FileSystemAccessDoRequestReadWritePermissionTest, WriteDenied) {
   auto handle = CreateHandle(kTestStorageKey, kTestURL,
                              base::FilePath::FromUTF8Unsafe("/test"));
 
@@ -358,7 +523,242 @@
     base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                            PermissionStatus>
         future;
-    DoRequestPermission(handle, /*writable=*/true, future);
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+        future);
+    EXPECT_EQ(future.Get<0>()->status,
+              blink::mojom::FileSystemAccessStatus::kOk);
+    EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
+    return;
+  }
+
+  // Read permission is already granted, so it should not be requested again.
+  EXPECT_CALL(*read_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+
+  EXPECT_CALL(
+      *write_grant_,
+      RequestPermission_(kFrameId, UserActivationState::kRequired, testing::_))
+      .WillOnce(testing::DoAll(
+          testing::InvokeWithoutArgs([&]() {
+            EXPECT_CALL(*write_grant_, GetStatus())
+                .WillOnce(testing::Return(PermissionStatus::DENIED));
+          }),
+          RunOnceCallback<2>(FileSystemAccessPermissionGrant::
+                                 PermissionRequestOutcome::kUserDenied)));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
+}
+
+// Tests that `DoRequestPermission` returns `DENIED` if write permission is
+// already denied when requesting both read & write permission.
+TEST_P(FileSystemAccessDoRequestReadWritePermissionTest, WriteAlreadyDenied) {
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+  EXPECT_CALL(*write_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::DENIED));
+
+  // No permission requests should be made.
+  EXPECT_CALL(*read_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+  EXPECT_CALL(*write_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
+}
+
+// The params for `DoRequestPermission()`-related tests.
+struct RequestPermissionOutcomeTestParam {
+  // The name of the test.
+  const char* test_name;
+  // The outcome of the permission request.
+  FileSystemAccessPermissionGrant::PermissionRequestOutcome outcome;
+  // The expected status of the request.
+  blink::mojom::FileSystemAccessStatus expected_status;
+  // The expected permission status.
+  PermissionStatus expected_permission_status;
+};
+
+// Testing the behavior of `DoRequestPermission` for read & write permission
+// requests.
+class FileSystemAccessDoRequestReadWritePermissionOutcomeTest
+    : public FileSystemAccessDoRequestPermissionTestBase,
+      public testing::WithParamInterface<
+          std::tuple<TestContextParam, RequestPermissionOutcomeTestParam>> {
+ public:
+  bool is_worker() const override { return std::get<0>(GetParam()).is_worker; }
+};
+
+// Tests that `DoRequestPermission` returns the correct status for a variety of
+// outcomes when read permission is already 'GRANTED'.
+TEST_P(FileSystemAccessDoRequestReadWritePermissionOutcomeTest,
+       ReadPermissionAlreadyGranted_WritePermissionOutcome) {
+  const RequestPermissionOutcomeTestParam& permission_param =
+      std::get<1>(GetParam());
+
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*read_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
+  EXPECT_CALL(*write_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+
+  if (is_worker()) {
+    // Workers can't show a permission prompt, so the permission status is
+    // expected to remain ASK.
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           PermissionStatus>
+        future;
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+        future);
+    EXPECT_EQ(future.Get<0>()->status,
+              blink::mojom::FileSystemAccessStatus::kOk);
+    EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
+    return;
+  }
+
+  EXPECT_CALL(
+      *write_grant_,
+      RequestPermission_(kFrameId, UserActivationState::kRequired, testing::_))
+      .WillOnce(RunOnceCallback<2>(permission_param.outcome));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, permission_param.expected_status);
+  EXPECT_EQ(future.Get<1>(), permission_param.expected_permission_status);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    FileSystemAccessDoRequestReadWritePermissionOutcomeTest,
+    testing::Combine(
+        testing::ValuesIn(kTestContextParams),
+        testing::Values(
+            RequestPermissionOutcomeTestParam{
+                "InvalidFrame",
+                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
+                    kInvalidFrame,
+                blink::mojom::FileSystemAccessStatus::kSecurityError,
+                PermissionStatus::ASK},
+            RequestPermissionOutcomeTestParam{
+                "NoUserActivation",
+                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
+                    kNoUserActivation,
+                blink::mojom::FileSystemAccessStatus::kSecurityError,
+                PermissionStatus::ASK},
+            RequestPermissionOutcomeTestParam{
+                "BlockedByContentSetting",
+                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
+                    kBlockedByContentSetting,
+                blink::mojom::FileSystemAccessStatus::kOk,
+                PermissionStatus::ASK},
+            RequestPermissionOutcomeTestParam{
+                "UserDenied",
+                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
+                    kUserDenied,
+                blink::mojom::FileSystemAccessStatus::kOk,
+                PermissionStatus::ASK})),
+    [](const testing::TestParamInfo<
+        std::tuple<TestContextParam, RequestPermissionOutcomeTestParam>>&
+           info) {
+      return std::string(std::get<0>(info.param).test_name) + "_" +
+             std::get<1>(info.param).test_name;
+    });
+
+class FileSystemAccessDoRequestWritePermissionTest
+    : public FileSystemAccessDoRequestPermissionTestBase,
+      public testing::WithParamInterface<TestContextParam> {
+ public:
+  bool is_worker() const override { return GetParam().is_worker; }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    FileSystemAccessDoRequestWritePermissionTest,
+    testing::ValuesIn(kTestContextParams),
+    [](const testing::TestParamInfo<TestContextParam>& info) {
+      return info.param.test_name;
+    });
+
+// Tests that `DoRequestPermission` with `kWrite` dies if the
+// `kFileSystemAccessWriteMode` feature is disabled.
+TEST_P(FileSystemAccessDoRequestWritePermissionTest, FeatureDisabled) {
+  base::test::ScopedFeatureList features;
+  features.InitAndDisableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  EXPECT_DEATH_IF_SUPPORTED(
+      DoRequestPermission(
+          handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future),
+      "");
+}
+
+// Tests that `DoRequestPermission` returns `GRANTED` if write permission is
+// already `GRANTED`.
+TEST_P(FileSystemAccessDoRequestWritePermissionTest, AlreadyGranted) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*write_grant_, GetStatus())
+      .WillOnce(testing::Return(PermissionStatus::GRANTED));
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::GRANTED);
+}
+
+// Tests that `DoRequestPermission` returns `GRANTED` if write permission is
+// granted when requested.
+TEST_P(FileSystemAccessDoRequestWritePermissionTest, Granted) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*write_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::ASK));
+
+  if (is_worker()) {
+    // Workers can't show a permission prompt, so the permission status is
+    // expected to remain ASK.
+    base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                           PermissionStatus>
+        future;
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future);
     EXPECT_EQ(future.Get<0>()->status,
               blink::mojom::FileSystemAccessStatus::kOk);
     EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
@@ -379,69 +779,20 @@
   base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                          PermissionStatus>
       future;
-  DoRequestPermission(handle, /*writable=*/true, future);
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future);
   EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
   EXPECT_EQ(future.Get<1>(), PermissionStatus::GRANTED);
 }
 
-// Tests that `DoRequestPermission` returns `GRANTED` if write permission is not
-// requested and read permission is already `GRANTED`.
-TEST_P(FileSystemAccessDoRequestPermissionTest, WritePermissionNotNeeded) {
+// Tests that `DoRequestPermission` returns `DENIED` if write permission is
+// denied when requesting write permission.
+TEST_P(FileSystemAccessDoRequestWritePermissionTest, Denied) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
   auto handle = CreateHandle(kTestStorageKey, kTestURL,
                              base::FilePath::FromUTF8Unsafe("/test"));
 
-  EXPECT_CALL(*read_grant_, GetStatus())
-      .WillOnce(testing::Return(PermissionStatus::GRANTED));
-
-  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
-                         PermissionStatus>
-      future;
-  DoRequestPermission(handle, /*writable=*/false, future);
-  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
-  EXPECT_EQ(future.Get<1>(), PermissionStatus::GRANTED);
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    FileSystemAccessDoRequestPermissionTest,
-    testing::ValuesIn(kTestContextParams),
-    [](const testing::TestParamInfo<TestContextParam>& info) {
-      return info.param.test_name;
-    });
-
-// The params for `FileSystemAccessDoRequestWritePermissionTest` test fixture.
-struct RequestWritePermissionTestParam {
-  // The name of the test.
-  const char* test_name;
-  // The outcome of the permission request.
-  FileSystemAccessPermissionGrant::PermissionRequestOutcome outcome;
-  // The expected status of the request.
-  blink::mojom::FileSystemAccessStatus expected_status;
-  // The expected permission status.
-  PermissionStatus expected_permission_status;
-};
-
-// Testing the behavior of `DoRequestPermission` for write permission requests.
-class FileSystemAccessDoRequestWritePermissionTest
-    : public FileSystemAccessDoRequestPermissionTestBase,
-      public testing::WithParamInterface<
-          std::tuple<TestContextParam, RequestWritePermissionTestParam>> {
- public:
-  bool is_worker() const override { return std::get<0>(GetParam()).is_worker; }
-};
-
-// Tests that `DoRequestPermission` returns the correct status for a variety of
-// outcomes.
-TEST_P(FileSystemAccessDoRequestWritePermissionTest,
-       ReadPermissionAlreadyGranted_WritePermissionOutcome) {
-  const RequestWritePermissionTestParam& permission_param =
-      std::get<1>(GetParam());
-
-  auto handle = CreateHandle(kTestStorageKey, kTestURL,
-                             base::FilePath::FromUTF8Unsafe("/test"));
-
-  EXPECT_CALL(*read_grant_, GetStatus())
-      .WillRepeatedly(testing::Return(PermissionStatus::GRANTED));
   EXPECT_CALL(*write_grant_, GetStatus())
       .WillRepeatedly(testing::Return(PermissionStatus::ASK));
 
@@ -451,7 +802,8 @@
     base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                            PermissionStatus>
         future;
-    DoRequestPermission(handle, /*writable=*/true, future);
+    DoRequestPermission(
+        handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future);
     EXPECT_EQ(future.Get<0>()->status,
               blink::mojom::FileSystemAccessStatus::kOk);
     EXPECT_EQ(future.Get<1>(), PermissionStatus::ASK);
@@ -461,51 +813,50 @@
   EXPECT_CALL(
       *write_grant_,
       RequestPermission_(kFrameId, UserActivationState::kRequired, testing::_))
-      .WillOnce(RunOnceCallback<2>(permission_param.outcome));
+      .WillOnce(testing::DoAll(
+          testing::InvokeWithoutArgs([&]() {
+            EXPECT_CALL(*write_grant_, GetStatus())
+                .WillOnce(testing::Return(PermissionStatus::DENIED));
+          }),
+          RunOnceCallback<2>(FileSystemAccessPermissionGrant::
+                                 PermissionRequestOutcome::kUserDenied)));
 
   base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
                          PermissionStatus>
       future;
-  DoRequestPermission(handle, /*writable=*/true, future);
-  EXPECT_EQ(future.Get<0>()->status, permission_param.expected_status);
-  EXPECT_EQ(future.Get<1>(), permission_param.expected_permission_status);
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    FileSystemAccessDoRequestWritePermissionTest,
-    testing::Combine(
-        testing::ValuesIn(kTestContextParams),
-        testing::Values(
-            RequestWritePermissionTestParam{
-                "InvalidFrame",
-                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
-                    kInvalidFrame,
-                blink::mojom::FileSystemAccessStatus::kSecurityError,
-                PermissionStatus::ASK},
-            RequestWritePermissionTestParam{
-                "NoUserActivation",
-                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
-                    kNoUserActivation,
-                blink::mojom::FileSystemAccessStatus::kSecurityError,
-                PermissionStatus::ASK},
-            RequestWritePermissionTestParam{
-                "BlockedByContentSetting",
-                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
-                    kBlockedByContentSetting,
-                blink::mojom::FileSystemAccessStatus::kOk,
-                PermissionStatus::ASK},
-            RequestWritePermissionTestParam{
-                "UserDenied",
-                FileSystemAccessPermissionGrant::PermissionRequestOutcome::
-                    kUserDenied,
-                blink::mojom::FileSystemAccessStatus::kOk,
-                PermissionStatus::ASK})),
-    [](const testing::TestParamInfo<
-        std::tuple<TestContextParam, RequestWritePermissionTestParam>>& info) {
-      return std::string(std::get<0>(info.param).test_name) + "_" +
-             std::get<1>(info.param).test_name;
-    });
+// Tests that `DoRequestPermission` returns `DENIED` if write permission is
+// already denied when requesting write permission.
+TEST_P(FileSystemAccessDoRequestWritePermissionTest, AlreadyDenied) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(blink::features::kFileSystemAccessWriteMode);
+  auto handle = CreateHandle(kTestStorageKey, kTestURL,
+                             base::FilePath::FromUTF8Unsafe("/test"));
+
+  EXPECT_CALL(*write_grant_, GetStatus())
+      .WillRepeatedly(testing::Return(PermissionStatus::DENIED));
+
+  // No permission requests should be made.
+  EXPECT_CALL(*read_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+  EXPECT_CALL(*write_grant_,
+              RequestPermission_(testing::_, testing::_, testing::_))
+      .Times(0);
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         PermissionStatus>
+      future;
+  DoRequestPermission(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kWrite, future);
+  EXPECT_EQ(future.Get<0>()->status, blink::mojom::FileSystemAccessStatus::kOk);
+  EXPECT_EQ(future.Get<1>(), PermissionStatus::DENIED);
+}
 
 class FileSystemAccessDoGetPermissionStatusTest
     : public FileSystemAccessHandleParamTestBase {
@@ -513,14 +864,14 @@
   // Calls `DoGetPermissionStatus` on the given `handle` and waits for the
   // result.
   void DoGetPermissionStatus(TestFileSystemAccessHandle& handle,
-                             bool writable,
+                             blink::mojom::FileSystemAccessPermissionMode mode,
                              base::test::TestFuture<PermissionStatus>& future) {
-    handle.DoGetPermissionStatus(writable, future.GetCallback());
+    handle.DoGetPermissionStatus(mode, future.GetCallback());
   }
 };
 
 // Tests `DoGetPermissionStatus` for read-only permission.
-TEST_P(FileSystemAccessDoGetPermissionStatusTest, WritableFalse) {
+TEST_P(FileSystemAccessDoGetPermissionStatusTest, Read) {
   auto handle = CreateHandle(kTestStorageKey, kTestURL,
                              base::FilePath::FromUTF8Unsafe("/test"));
 
@@ -528,12 +879,13 @@
       .WillOnce(testing::Return(PermissionStatus::ASK));
 
   base::test::TestFuture<PermissionStatus> future;
-  DoGetPermissionStatus(handle, /*writable=*/false, future);
+  DoGetPermissionStatus(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kRead, future);
   EXPECT_EQ(future.Get(), PermissionStatus::ASK);
 }
 
-// Tests `DoGetPermissionStatus` for writable permission.
-TEST_P(FileSystemAccessDoGetPermissionStatusTest, WritableTrue) {
+// Tests `DoGetPermissionStatus` for read & write permission.
+TEST_P(FileSystemAccessDoGetPermissionStatusTest, ReadWrite) {
   auto handle = CreateHandle(kTestStorageKey, kTestURL,
                              base::FilePath::FromUTF8Unsafe("/test"));
 
@@ -543,7 +895,8 @@
       .WillOnce(testing::Return(PermissionStatus::ASK));
 
   base::test::TestFuture<PermissionStatus> future;
-  DoGetPermissionStatus(handle, /*writable=*/true, future);
+  DoGetPermissionStatus(
+      handle, blink::mojom::FileSystemAccessPermissionMode::kReadWrite, future);
   EXPECT_EQ(future.Get(), PermissionStatus::ASK);
 }
 
diff --git a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
index 88b3562f..7e845e9 100644
--- a/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
+++ b/content/browser/file_system_access/file_system_access_manager_impl_unittest.cc
@@ -198,9 +198,11 @@
   }
 
   template <typename HandleType>
-  PermissionStatus GetPermissionStatusSync(bool writable, HandleType* handle) {
+  PermissionStatus GetPermissionStatusSync(
+      blink::mojom::FileSystemAccessPermissionMode mode,
+      HandleType* handle) {
     base::test::TestFuture<PermissionStatus> future;
-    handle->GetPermissionStatus(writable, future.GetCallback());
+    handle->GetPermissionStatus(mode, future.GetCallback());
     return future.Get();
   }
 
@@ -449,6 +451,10 @@
       base::MakeRefCounted<FixedFileSystemAccessPermissionGrant>(
           FixedFileSystemAccessPermissionGrant::PermissionStatus::GRANTED,
           PathInfo());
+  scoped_refptr<FixedFileSystemAccessPermissionGrant> deny_grant_ =
+      base::MakeRefCounted<FixedFileSystemAccessPermissionGrant>(
+          FixedFileSystemAccessPermissionGrant::PermissionStatus::DENIED,
+          PathInfo());
 };
 
 TEST_F(FileSystemAccessManagerImplTest, GetSandboxedFileSystem_CreateBucket) {
@@ -580,10 +586,14 @@
   mojo::Remote<blink::mojom::FileSystemAccessDirectoryHandle> root(
       std::move(directory_remote));
   ASSERT_TRUE(root);
+  EXPECT_EQ(
+      PermissionStatus::GRANTED,
+      GetPermissionStatusSync(
+          blink::mojom::FileSystemAccessPermissionMode::kRead, root.get()));
   EXPECT_EQ(PermissionStatus::GRANTED,
-            GetPermissionStatusSync(/*writable=*/false, root.get()));
-  EXPECT_EQ(PermissionStatus::GRANTED,
-            GetPermissionStatusSync(/*writable=*/true, root.get()));
+            GetPermissionStatusSync(
+                blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                root.get()));
 }
 
 TEST_F(FileSystemAccessManagerImplTest, CreateFileEntryFromPath_Permissions) {
@@ -607,10 +617,14 @@
   mojo::Remote<blink::mojom::FileSystemAccessFileHandle> handle(
       std::move(entry->entry_handle->get_file()));
 
-  EXPECT_EQ(PermissionStatus::GRANTED,
-            GetPermissionStatusSync(/*writable=*/false, handle.get()));
+  EXPECT_EQ(
+      PermissionStatus::GRANTED,
+      GetPermissionStatusSync(
+          blink::mojom::FileSystemAccessPermissionMode::kRead, handle.get()));
   EXPECT_EQ(PermissionStatus::ASK,
-            GetPermissionStatusSync(/*writable=*/true, handle.get()));
+            GetPermissionStatusSync(
+                blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                handle.get()));
 }
 
 TEST_F(FileSystemAccessManagerImplTest,
@@ -635,10 +649,14 @@
   mojo::Remote<blink::mojom::FileSystemAccessFileHandle> handle(
       std::move(entry->entry_handle->get_file()));
 
+  EXPECT_EQ(
+      PermissionStatus::GRANTED,
+      GetPermissionStatusSync(
+          blink::mojom::FileSystemAccessPermissionMode::kRead, handle.get()));
   EXPECT_EQ(PermissionStatus::GRANTED,
-            GetPermissionStatusSync(/*writable=*/false, handle.get()));
-  EXPECT_EQ(PermissionStatus::GRANTED,
-            GetPermissionStatusSync(/*writable=*/true, handle.get()));
+            GetPermissionStatusSync(
+                blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                handle.get()));
 }
 
 TEST_F(FileSystemAccessManagerImplTest,
@@ -664,10 +682,14 @@
           FileSystemAccessPermissionContext::UserAction::kOpen);
   mojo::Remote<blink::mojom::FileSystemAccessDirectoryHandle> handle(
       std::move(entry->entry_handle->get_directory()));
-  EXPECT_EQ(PermissionStatus::GRANTED,
-            GetPermissionStatusSync(/*writable=*/false, handle.get()));
+  EXPECT_EQ(
+      PermissionStatus::GRANTED,
+      GetPermissionStatusSync(
+          blink::mojom::FileSystemAccessPermissionMode::kRead, handle.get()));
   EXPECT_EQ(PermissionStatus::ASK,
-            GetPermissionStatusSync(/*writable=*/true, handle.get()));
+            GetPermissionStatusSync(
+                blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                handle.get()));
 }
 
 TEST_F(FileSystemAccessManagerImplTest,
@@ -1896,6 +1918,106 @@
 }
 
 TEST_F(FileSystemAccessManagerImplTest,
+       ChooseEntries_OpenDirectory_ReadWrite_WriteDenied) {
+  PathInfo test_dir_info(dir_.GetPath());
+
+  manager_->SetFilePickerResultForTesting(test_dir_info);
+
+  static_cast<TestRenderFrameHost*>(web_contents_->GetPrimaryMainFrame())
+      ->SimulateUserActivation();
+
+  mojo::Remote<blink::mojom::FileSystemAccessManager> manager_remote;
+  FileSystemAccessManagerImpl::BindingContext binding_context = {
+      kTestStorageKey, kTestURL,
+      web_contents_->GetPrimaryMainFrame()->GetGlobalId()};
+  manager_->BindReceiver(binding_context,
+                         manager_remote.BindNewPipeAndPassReceiver());
+
+  EXPECT_CALL(permission_context_,
+              CanObtainReadPermission(kTestStorageKey.origin()))
+      .WillOnce(testing::Return(true));
+  EXPECT_CALL(permission_context_,
+              CanObtainWritePermission(kTestStorageKey.origin()))
+      .WillOnce(testing::Return(true));
+
+  EXPECT_CALL(
+      permission_context_,
+      GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory::kDirDocuments,
+                                kTestStorageKey.origin()))
+      .WillOnce(testing::Return(base::FilePath()));
+  EXPECT_CALL(permission_context_,
+              GetLastPickedDirectory(kTestStorageKey.origin(), std::string()))
+      .WillOnce(testing::Return(PathInfo()));
+  EXPECT_CALL(permission_context_, GetPickerTitle(testing::_))
+      .WillOnce(testing::Return(std::u16string()));
+  EXPECT_CALL(permission_context_,
+              SetLastPickedDirectory(kTestStorageKey.origin(), std::string(),
+                                     test_dir_info));
+
+  EXPECT_CALL(
+      permission_context_,
+      ConfirmSensitiveEntryAccess_(
+          kTestStorageKey.origin(), test_dir_info,
+          FileSystemAccessPermissionContext::HandleType::kDirectory,
+          FileSystemAccessPermissionContext::UserAction::kOpen,
+          web_contents_->GetPrimaryMainFrame()->GetGlobalId(), testing::_))
+      .WillOnce(RunOnceCallback<5>(
+          FileSystemAccessPermissionContext::SensitiveEntryResult::kAllowed));
+
+  EXPECT_CALL(permission_context_,
+              GetReadPermissionGrant(
+                  kTestStorageKey.origin(), test_dir_info,
+                  FileSystemAccessPermissionContext::HandleType::kDirectory,
+                  FileSystemAccessPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(allow_grant_));
+  EXPECT_CALL(permission_context_,
+              GetWritePermissionGrant(
+                  kTestStorageKey.origin(), test_dir_info,
+                  FileSystemAccessPermissionContext::HandleType::kDirectory,
+                  FileSystemAccessPermissionContext::UserAction::kOpen))
+      .WillOnce(testing::Return(deny_grant_));
+  EXPECT_CALL(permission_context_, CheckPathsAgainstEnterprisePolicy(
+                                       testing::_, testing::_, testing::_))
+      .WillOnce(testing::Invoke(
+          [](std::vector<PathInfo> entries,
+             content::GlobalRenderFrameHostId frame_id,
+             MockFileSystemAccessPermissionContext::
+                 EntriesAllowedByEnterprisePolicyCallback callback) {
+            std::move(callback).Run(std::move(entries));
+          }));
+
+  auto picker_options = blink::mojom::FilePickerOptions::New(
+      blink::mojom::TypeSpecificFilePickerOptionsUnion::
+          NewDirectoryPickerOptions(blink::mojom::DirectoryPickerOptions::New(
+              blink::mojom::FileSystemAccessPermissionMode::kReadWrite)),
+      /*starting_directory_id=*/std::string(),
+      blink::mojom::FilePickerStartInOptionsUnionPtr());
+
+  base::test::TestFuture<blink::mojom::FileSystemAccessErrorPtr,
+                         std::vector<blink::mojom::FileSystemAccessEntryPtr>>
+      future;
+  manager_remote->ChooseEntries(std::move(picker_options),
+                                future.GetCallback());
+  ASSERT_TRUE(future.Wait());
+
+  auto& [error, entries] = future.Get();
+  EXPECT_EQ(error->status, blink::mojom::FileSystemAccessStatus::kOk);
+  ASSERT_EQ(entries.size(), 1u);
+  ASSERT_TRUE(entries[0]->entry_handle->is_directory());
+  mojo::Remote<blink::mojom::FileSystemAccessDirectoryHandle> handle(
+      std::move(entries[0]->entry_handle->get_directory()));
+
+  EXPECT_EQ(
+      PermissionStatus::GRANTED,
+      GetPermissionStatusSync(
+          blink::mojom::FileSystemAccessPermissionMode::kRead, handle.get()));
+  EXPECT_EQ(PermissionStatus::DENIED,
+            GetPermissionStatusSync(
+                blink::mojom::FileSystemAccessPermissionMode::kReadWrite,
+                handle.get()));
+}
+
+TEST_F(FileSystemAccessManagerImplTest,
        ChooseEntries_OpenDirectory_EnterpriseBlock) {
   PathInfo test_dir_info(dir_.GetPath());
 
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding_decodeidbkeypath_fuzzer.cc b/content/browser/indexed_db/indexed_db_leveldb_coding_decodeidbkeypath_fuzzer.cc
index fb70848..cec7d24 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding_decodeidbkeypath_fuzzer.cc
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding_decodeidbkeypath_fuzzer.cc
@@ -13,14 +13,33 @@
 #include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  std::string_view key_path_str_view(reinterpret_cast<const char*>(data), size);
+  std::string_view parsed_input(reinterpret_cast<const char*>(data), size);
+  std::string_view input(parsed_input);
   blink::IndexedDBKeyPath indexed_db_key_path;
-  if (content::indexed_db::DecodeIDBKeyPath(&key_path_str_view,
+  if (content::indexed_db::DecodeIDBKeyPath(&parsed_input,
                                             &indexed_db_key_path)) {
     // Ensure that encoding |indexed_db_key_path| produces the same result.
     std::string result;
     content::indexed_db::EncodeIDBKeyPath(indexed_db_key_path, &result);
-    CHECK_EQ(std::string_view(result), key_path_str_view);
+
+    input.remove_suffix(parsed_input.size());
+
+    // There is an old style of encoding where the type is not encoded, and the
+    // keypath is just a string. In this case, when we re-encode, the output
+    // *will* encode the type, and this format takes 6 extra bytes.
+    if (input.size() >= 3 && input[0] != 0 && input[1] != 0) {
+      CHECK_EQ(indexed_db_key_path.type(),
+               blink::mojom::IDBKeyPathType::String);
+      CHECK_EQ(result.size(), input.size() + 6);
+
+      std::string_view reencoded(result);
+      blink::IndexedDBKeyPath redecoded;
+      CHECK(content::indexed_db::DecodeIDBKeyPath(&reencoded, &redecoded));
+      CHECK_EQ(redecoded.string(), indexed_db_key_path.string());
+      return 0;
+    }
+
+    CHECK_EQ(std::string_view(result), input);
   }
   return 0;
 }
diff --git a/content/browser/indexed_db/instance/sqlite/database_connection.cc b/content/browser/indexed_db/instance/sqlite/database_connection.cc
index 0387905..b7e504e 100644
--- a/content/browser/indexed_db/instance/sqlite/database_connection.cc
+++ b/content/browser/indexed_db/instance/sqlite/database_connection.cc
@@ -49,32 +49,44 @@
 // type array. Spaces are not allowed in the individual strings, which makes
 // this a convenient choice.
 constexpr char16_t kKeyPathSeparator[] = u" ";
-
-// Encodes `key_path` into a string. The key path can be either a string or an
-// array of strings. If it is an array, the contents are joined with
-// `kKeyPathSeparator`.
-std::u16string EncodeKeyPath(const blink::IndexedDBKeyPath& key_path) {
+void BindKeyPath(sql::Statement& statement,
+                 int param_index,
+                 const blink::IndexedDBKeyPath& key_path) {
   switch (key_path.type()) {
     case blink::mojom::IDBKeyPathType::Null:
-      return std::u16string();
+      statement.BindNull(param_index);
+      break;
     case blink::mojom::IDBKeyPathType::String:
-      return key_path.string();
+      statement.BindBlob(param_index, key_path.string());
+      break;
     case blink::mojom::IDBKeyPathType::Array:
-      return base::JoinString(key_path.array(), kKeyPathSeparator);
+      statement.BindBlob(param_index,
+                         base::JoinString(key_path.array(), kKeyPathSeparator));
+      break;
     default:
       NOTREACHED();
   }
 }
-blink::IndexedDBKeyPath DecodeKeyPath(const std::u16string& encoded) {
-  if (encoded.empty()) {
+blink::IndexedDBKeyPath ColumnKeyPath(sql::Statement& statement,
+                                      int column_index) {
+  if (statement.GetColumnType(column_index) == sql::ColumnType::kNull) {
+    // `Null` key path.
     return blink::IndexedDBKeyPath();
   }
+  std::u16string encoded;
+  TRANSIENT_CHECK(statement.ColumnBlobAsString16(column_index, &encoded));
   std::vector<std::u16string> parts = base::SplitString(
       encoded, kKeyPathSeparator, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-  if (parts.size() > 1) {
-    return blink::IndexedDBKeyPath(std::move(parts));
+  if (parts.empty()) {
+    // Empty `String` key path.
+    return blink::IndexedDBKeyPath(std::u16string());
   }
-  return blink::IndexedDBKeyPath(std::move(parts.front()));
+  if (parts.size() == 1) {
+    // Non-empty `String` key path.
+    return blink::IndexedDBKeyPath(std::move(parts.front()));
+  }
+  // `Array` key path.
+  return blink::IndexedDBKeyPath(std::move(parts));
 }
 
 // These are schema versions of our implementation of `sql::Database`; not the
@@ -122,7 +134,7 @@
       db->Execute("CREATE TABLE object_stores "
                   "(id INTEGER PRIMARY KEY,"
                   " name BLOB NOT NULL,"
-                  " key_path BLOB NOT NULL,"
+                  " key_path BLOB,"
                   " auto_increment INTEGER NOT NULL,"
                   " key_generator_current_number INTEGER NOT NULL)"));
   TRANSIENT_CHECK(
@@ -130,7 +142,7 @@
                   "(object_store_id INTEGER NOT NULL,"
                   " id INTEGER NOT NULL,"
                   " name BLOB NOT NULL,"
-                  " key_path BLOB NOT NULL,"
+                  " key_path BLOB,"
                   " is_unique INTEGER NOT NULL,"
                   " multi_entry INTEGER NOT NULL,"
                   " PRIMARY KEY (object_store_id, id)"
@@ -258,9 +270,7 @@
       blink::IndexedDBObjectStoreMetadata store_metadata;
       store_metadata.id = statement.ColumnInt64(0);
       TRANSIENT_CHECK(statement.ColumnBlobAsString16(1, &store_metadata.name));
-      std::u16string encoded_key_path;
-      TRANSIENT_CHECK(statement.ColumnBlobAsString16(2, &encoded_key_path));
-      store_metadata.key_path = DecodeKeyPath(encoded_key_path);
+      store_metadata.key_path = ColumnKeyPath(statement, 2);
       store_metadata.auto_increment = statement.ColumnBool(3);
       max_object_store_id = std::max(max_object_store_id, store_metadata.id);
       metadata.object_stores[store_metadata.id] = std::move(store_metadata);
@@ -279,9 +289,7 @@
       int64_t object_store_id = statement.ColumnInt64(0);
       index_metadata.id = statement.ColumnInt64(1);
       TRANSIENT_CHECK(statement.ColumnBlobAsString16(2, &index_metadata.name));
-      std::u16string encoded_key_path;
-      TRANSIENT_CHECK(statement.ColumnBlobAsString16(3, &encoded_key_path));
-      index_metadata.key_path = DecodeKeyPath(encoded_key_path);
+      index_metadata.key_path = ColumnKeyPath(statement, 3);
       index_metadata.unique = statement.ColumnBool(4);
       index_metadata.multi_entry = statement.ColumnBool(5);
       blink::IndexedDBObjectStoreMetadata& store_metadata =
@@ -868,6 +876,8 @@
     // Nothing to do.
     return Status::OK();
   }
+  // No need to sync active blobs when the transaction successfully commits.
+  sync_active_blobs_after_transaction_ = false;
   TRANSIENT_CHECK(active_rw_transaction_->Commit());
   if (transaction.mode() == blink::mojom::IDBTransactionMode::VersionChange) {
     CHECK(metadata_snapshot_.has_value());
@@ -910,6 +920,38 @@
   // there were no statements executed anyway.
   CHECK(active_rw_transaction_);
   active_rw_transaction_.reset();
+
+  // If the transaction is rolled back, recent changes to the blob_references
+  // table may be lost. Make sure that table is up to date with memory state.
+  if (sync_active_blobs_after_transaction_) {
+    sql::Transaction sql_transaction(db_.get());
+    TRANSIENT_CHECK(sql_transaction.Begin());
+
+    // Step 1, mark existing active references with an invalid (but not null)
+    // row id. This can't immediately remove them as that could trigger cleanup
+    // of the underlying blob.
+    {
+      sql::Statement statement(
+          db_->GetCachedStatement(SQL_FROM_HERE,
+                                  "UPDATE blob_references SET record_row_id = 0"
+                                  "   WHERE record_row_id IS NULL"));
+      TRANSIENT_CHECK(statement.Run());
+    }
+    // Step 2, make add all the active references.
+    for (auto& [blob_number, _] : active_blobs_) {
+      AddActiveBlobReference(blob_number);
+    }
+    // Step 3, remove the old references.
+    {
+      sql::Statement statement(db_->GetCachedStatement(
+          SQL_FROM_HERE,
+          "DELETE FROM blob_references WHERE record_row_id = 0"));
+      TRANSIENT_CHECK(statement.Run());
+    }
+
+    TRANSIENT_CHECK(sql_transaction.Commit());
+    sync_active_blobs_after_transaction_ = false;
+  }
 }
 
 Status DatabaseConnection::SetDatabaseVersion(
@@ -945,7 +987,7 @@
       "VALUES (?, ?, ?, ?, ?)"));
   statement.BindInt64(0, metadata.id);
   statement.BindBlob(1, metadata.name);
-  statement.BindBlob(2, EncodeKeyPath(metadata.key_path));
+  BindKeyPath(statement, 2, metadata.key_path);
   statement.BindBool(3, metadata.auto_increment);
   statement.BindInt64(4, ObjectStoreMetaDataKey::kKeyGeneratorInitialNumber);
   TRANSIENT_CHECK(statement.Run());
@@ -1032,7 +1074,7 @@
   statement.BindInt64(0, object_store_id);
   statement.BindInt64(1, index_id);
   statement.BindBlob(2, index.name);
-  statement.BindBlob(3, EncodeKeyPath(index.key_path));
+  BindKeyPath(statement, 3, index.key_path);
   statement.BindBool(4, index.unique);
   statement.BindBool(5, index.multi_entry);
   TRANSIENT_CHECK(statement.Run());
@@ -1442,14 +1484,7 @@
                          base::Unretained(this), object.blob_number()));
       it = active_blobs_.insert({object.blob_number(), std::move(streamer)})
                .first;
-
-      {
-        sql::Statement statement(db_->GetCachedStatement(
-            SQL_FROM_HERE,
-            "INSERT INTO blob_references (blob_row_id) VALUES (?)"));
-        statement.BindInt64(0, object.blob_number());
-        TRANSIENT_CHECK(statement.Run());
-      }
+      AddActiveBlobReference(object.blob_number());
     }
     it->second->AddReceiver(std::move(receiver),
                             backing_store_->blob_storage_context());
@@ -1493,11 +1528,26 @@
 void DatabaseConnection::OnBlobBecameInactive(int64_t blob_number) {
   CHECK_EQ(active_blobs_.erase(blob_number), 1U);
 
+  RemoveActiveBlobReference(blob_number);
+}
+
+void DatabaseConnection::AddActiveBlobReference(int64_t blob_number) {
+  if (active_rw_transaction_) {
+    sync_active_blobs_after_transaction_ = true;
+  }
+
+  sql::Statement statement(db_->GetCachedStatement(
+      SQL_FROM_HERE, "INSERT INTO blob_references (blob_row_id) VALUES (?)"));
+  statement.BindInt64(0, blob_number);
+  TRANSIENT_CHECK(statement.Run());
+}
+
+void DatabaseConnection::RemoveActiveBlobReference(int64_t blob_number) {
+  if (active_rw_transaction_) {
+    sync_active_blobs_after_transaction_ = true;
+  }
+
   {
-    // TODO(crbug.com/419208485): If this operation happens in the middle of a
-    // r/w txn that is not committed (Chromium crashes or txn gets rolled back),
-    // the blob will come back from the dead! `this` should run this statement
-    // after any active r/w txn.
     sql::Statement statement(
         db_->GetCachedStatement(SQL_FROM_HERE,
                                 "DELETE FROM blob_references "
diff --git a/content/browser/indexed_db/instance/sqlite/database_connection.h b/content/browser/indexed_db/instance/sqlite/database_connection.h
index 65a6e5a..15e4f33 100644
--- a/content/browser/indexed_db/instance/sqlite/database_connection.h
+++ b/content/browser/indexed_db/instance/sqlite/database_connection.h
@@ -240,6 +240,14 @@
   // when `ActiveBlobStreamer` in `active_blobs_` no longer has connections.
   void OnBlobBecameInactive(int64_t blob_number);
 
+  // These methods add or remove rows to the `blob_references` table. The rows
+  // correspond to active blobs, i.e. the `record_row_id` will be null. These
+  // updates are made right away when `active_blobs_` is updated (an element is
+  // added or removed), and also after a transaction is rolled back which may
+  // have caused the loss of a `blob_references` update.
+  void AddActiveBlobReference(int64_t blob_number);
+  void RemoveActiveBlobReference(int64_t blob_number);
+
   // The connection needs to be held open when there are active blobs or an
   // active BackingStore::Database referencing it. This will return false if
   // that's the case.
@@ -247,6 +255,7 @@
 
   // The expected path for `db_`, or empty for in-memory DBs.
   const base::FilePath path_;
+
   std::unique_ptr<sql::Database> db_;
   std::unique_ptr<sql::MetaTable> meta_table_;
   blink::IndexedDBDatabaseMetadata metadata_;
@@ -294,6 +303,13 @@
   // alive since they're backed by the SQLite database.
   std::map<int64_t, std::unique_ptr<ActiveBlobStreamer>> active_blobs_;
 
+  // Used to track when rolling back a transaction necessitates updating
+  // `blob_references`. Transaction rollback will affect `blob_references`
+  // updates that have been made since the transaction started, but we need that
+  // table to stay in sync with `active_blobs_` regardless of whether the
+  // transaction is ultimately committed or rolled back.
+  bool sync_active_blobs_after_transaction_ = false;
+
   // TODO(crbug.com/419203257): this should invalidate its weak pointers when
   // `db_` is closed.
   base::WeakPtrFactory<DatabaseConnection> record_iterator_weak_factory_{this};
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index d11643b..beb9ff5 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -111,85 +111,6 @@
   base::test::ScopedFeatureList split_cache_enabled_feature_list_;
 };
 
-class PrefetchBrowserTestPrivacyChanges
-    : public PrefetchBrowserTestBase,
-      public testing::WithParamInterface<bool> {
- public:
-  PrefetchBrowserTestPrivacyChanges()
-      : privacy_changes_enabled_(GetParam()),
-        cross_origin_server_(std::make_unique<net::EmbeddedTestServer>()) {}
-
-  PrefetchBrowserTestPrivacyChanges(const PrefetchBrowserTestPrivacyChanges&) =
-      delete;
-  PrefetchBrowserTestPrivacyChanges& operator=(
-      const PrefetchBrowserTestPrivacyChanges&) = delete;
-
-  ~PrefetchBrowserTestPrivacyChanges() override = default;
-
-  void SetUp() override {
-    std::vector<base::test::FeatureRef> enable_features;
-    std::vector<base::test::FeatureRef> disabled_features;
-    if (privacy_changes_enabled_) {
-      enable_features.push_back(blink::features::kPrefetchPrivacyChanges);
-    } else {
-      disabled_features.push_back(blink::features::kPrefetchPrivacyChanges);
-    }
-    feature_list_.InitWithFeatures(enable_features, disabled_features);
-    PrefetchBrowserTestBase::SetUp();
-  }
-
- protected:
-  const bool privacy_changes_enabled_;
-  std::unique_ptr<net::EmbeddedTestServer> cross_origin_server_;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-// Test flakes.
-// TODO(crbug.com/40248957): Resolve flake and reenable.
-IN_PROC_BROWSER_TEST_P(PrefetchBrowserTestPrivacyChanges,
-                       DISABLED_RedirectNotFollowed) {
-  const char* prefetch_path = "/prefetch.html";
-  const char* redirect_path = "/redirect.html";
-  const char* destination_path = "/destination.html";
-  RegisterResponse(
-      prefetch_path,
-      ResponseEntry(base::StringPrintf(
-          "<body><link rel='prefetch' href='%s'></body>", redirect_path)));
-  RegisterResponse(
-      redirect_path,
-      ResponseEntry("", "", {{"location", std::string(destination_path)}},
-                    net::HTTP_MOVED_PERMANENTLY));
-  RegisterResponse(destination_path,
-                   ResponseEntry("<head><title>Prefetch Target</title></head>",
-                                 "text/html", {{"cache-control", "no-store"}}));
-
-  base::RunLoop prefetch_waiter;
-  auto main_page_counter = RequestCounter::CreateAndMonitor(
-      embedded_test_server(), prefetch_path, &prefetch_waiter);
-  auto destination_counter = RequestCounter::CreateAndMonitor(
-      embedded_test_server(), destination_path);
-  RegisterRequestHandler(embedded_test_server());
-  ASSERT_TRUE(embedded_test_server()->Start());
-  EXPECT_EQ(0, main_page_counter->GetRequestCount());
-  EXPECT_EQ(0, destination_counter->GetRequestCount());
-  EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
-
-  const GURL destination_url = embedded_test_server()->GetURL(destination_path);
-  // Loading a page that prefetches the redirect resource only follows the
-  // redirect when the mode is follow.
-  EXPECT_TRUE(
-      NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
-  prefetch_waiter.Run();
-  EXPECT_EQ(1, main_page_counter->GetRequestCount());
-
-  NavigateToURLAndWaitTitle(destination_url, "Prefetch Target");
-  const int expected_request_count = privacy_changes_enabled_ ? 1 : 2;
-  EXPECT_EQ(expected_request_count, destination_counter->GetRequestCount());
-  EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
-}
-
 // TODO(crbug.com/40256279): De-flake and re-enable.
 IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
                        DISABLED_CrossOriginDocumentHasNoSameSiteCookies) {
@@ -1658,8 +1579,4 @@
       }
     });
 
-INSTANTIATE_TEST_SUITE_P(PrefetchBrowserTestPrivacyChanges,
-                         PrefetchBrowserTestPrivacyChanges,
-                         testing::Bool());
-
 }  // namespace content
diff --git a/content/browser/loader/prefetch_url_loader_service_context.cc b/content/browser/loader/prefetch_url_loader_service_context.cc
index 4893bb77..dc5c7b5 100644
--- a/content/browser/loader/prefetch_url_loader_service_context.cc
+++ b/content/browser/loader/prefetch_url_loader_service_context.cc
@@ -216,15 +216,6 @@
     return false;
   }
 
-  // If the PrefetchPrivacyChanges feature is enabled, the request's redirect
-  // mode must be |kError|.
-  if (base::FeatureList::IsEnabled(blink::features::kPrefetchPrivacyChanges) &&
-      resource_request.redirect_mode != network::mojom::RedirectMode::kError) {
-    loader_factory_receivers_->ReportBadMessage(
-        "Prefetch/IsValidCrossOrigin: wrong redirect mode");
-    return false;
-  }
-
   // This prefetch request must not be able to reuse restricted prefetches from
   // the prefetch cache. This is because it is possible that another origin
   // prefetched the same resource, which should only be reused for top-level
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 1bdfac8..82438d8 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -803,6 +803,16 @@
   return routed_service_->GetRenderFrameHost();
 }
 
+std::optional<media_session::MediaPosition>
+MediaSessionImpl::GetMediaSessionPosition() {
+  return position_;
+}
+
+const media_session::MediaMetadata&
+MediaSessionImpl::GetMediaSessionMetadata() {
+  return metadata_;
+}
+
 void MediaSessionImpl::StartDucking() {
   should_unduck_on_focus_gained_ = false;
   if (is_ducking_)
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index 3b12f73f..3c0a98fe 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -178,10 +178,6 @@
   // Creates a binding between |this| and |request|.
   mojo::PendingRemote<media_session::mojom::MediaSession> AddRemote();
 
-  // Returns information about the MediaSession.
-  CONTENT_EXPORT media_session::mojom::MediaSessionInfoPtr
-  GetMediaSessionInfoSync();
-
   // Returns if the session can be controlled by the user.
   CONTENT_EXPORT bool IsControllable() const;
 
@@ -214,8 +210,22 @@
 
   // Returns the `RenderFrameHost` for the currently MediaSession routed
   // service.
+  // TODO(crbug.com/409427125): Also return a frame if no service is created for
+  // a player.
   RenderFrameHost* GetRoutedFrame() override;
 
+  // Returns the current media session info synchronously for a one-off request.
+  CONTENT_EXPORT media_session::mojom::MediaSessionInfoPtr
+  GetMediaSessionInfoSync() override;
+
+  // Returns the current media session position for a one-off request.
+  CONTENT_EXPORT std::optional<media_session::MediaPosition>
+  GetMediaSessionPosition() override;
+
+  // Returns the current media session metadata for a one-off request.
+  CONTENT_EXPORT const media_session::MediaMetadata& GetMediaSessionMetadata()
+      override;
+
   // Suspend the media session.
   // |type| represents the origin of the request.
   CONTENT_EXPORT void Suspend(MediaSession::SuspendType suspend_type) override;
diff --git a/content/browser/metrics/histogram_synchronizer.cc b/content/browser/metrics/histogram_synchronizer.cc
index 9ca9684..6b9427a 100644
--- a/content/browser/metrics/histogram_synchronizer.cc
+++ b/content/browser/metrics/histogram_synchronizer.cc
@@ -9,10 +9,10 @@
 #include "base/check_op.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/metrics/histogram_delta_serialization.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "base/pickle.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/thread.h"
@@ -86,7 +86,7 @@
 
     RequestContext* request =
         new RequestContext(std::move(callback), sequence_number);
-    outstanding_requests_.Get()[sequence_number] = request;
+    GetOutstandingRequests()[sequence_number] = request;
   }
 
   // Find the |RequestContext| in |outstanding_requests_| map for the given
@@ -94,9 +94,10 @@
   static RequestContext* GetRequestContext(int sequence_number) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    auto it = outstanding_requests_.Get().find(sequence_number);
-    if (it == outstanding_requests_.Get().end())
+    auto it = GetOutstandingRequests().find(sequence_number);
+    if (it == GetOutstandingRequests().end()) {
       return nullptr;
+    }
 
     RequestContext* request = it->second;
     DCHECK_EQ(sequence_number, request->sequence_number_);
@@ -109,28 +110,36 @@
   static void Unregister(int sequence_number) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-    auto it = outstanding_requests_.Get().find(sequence_number);
-    if (it == outstanding_requests_.Get().end())
+    auto it = GetOutstandingRequests().find(sequence_number);
+    if (it == GetOutstandingRequests().end()) {
       return;
+    }
 
     RequestContext* request = it->second;
     DCHECK_EQ(sequence_number, request->sequence_number_);
     std::move(request->callback_).Run();
 
     delete request;
-    outstanding_requests_.Get().erase(it);
+    GetOutstandingRequests().erase(it);
   }
 
   // Delete all the entries in |outstanding_requests_| map.
   static void OnShutdown() {
     // Just in case we have any pending tasks, clear them out.
-    while (!outstanding_requests_.Get().empty()) {
-      auto it = outstanding_requests_.Get().begin();
+    while (!GetOutstandingRequests().empty()) {
+      auto it = GetOutstandingRequests().begin();
       delete it->second;
-      outstanding_requests_.Get().erase(it);
+      GetOutstandingRequests().erase(it);
     }
   }
 
+  // Map of all outstanding RequestContexts, from sequence_number_ to
+  // RequestContext.
+  static RequestContextMap& GetOutstandingRequests() {
+    static base::NoDestructor<RequestContextMap> outstanding_requests;
+    return *outstanding_requests;
+  }
+
   // Requests are made to asynchronously send data to the |callback_|.
   base::OnceClosure callback_;
 
@@ -144,17 +153,8 @@
   // The number of pending processes (all renderer processes and browser child
   // processes) that have not yet responded to requests.
   int processes_pending_;
-
-  // Map of all outstanding RequestContexts, from sequence_number_ to
-  // RequestContext.
-  static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
 };
 
-// static
-base::LazyInstance<HistogramSynchronizer::RequestContext::RequestContextMap>::
-    Leaky HistogramSynchronizer::RequestContext::outstanding_requests_ =
-        LAZY_INSTANCE_INITIALIZER;
-
 HistogramSynchronizer::HistogramSynchronizer()
     : lock_(),
       last_used_sequence_number_(kNeverUsableSequenceNumber),
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 71c6d4f7..354b973 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -95,7 +95,6 @@
 #include "content/test/render_document_feature.h"
 #include "content/test/task_runner_deferring_throttle.h"
 #include "content/test/test_render_frame_host_factory.h"
-#include "ipc/ipc_security_test_util.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "net/base/features.h"
diff --git a/content/browser/preloading/prerender/prerender_attributes.cc b/content/browser/preloading/prerender/prerender_attributes.cc
index 59daf4be..cdc193f 100644
--- a/content/browser/preloading/prerender/prerender_attributes.cc
+++ b/content/browser/preloading/prerender/prerender_attributes.cc
@@ -31,6 +31,7 @@
     ui::PageTransition transition_type,
     bool should_warm_up_compositor,
     bool should_prepare_paint_tree,
+    bool should_pause_javascript_execution,
     base::RepeatingCallback<bool(const GURL&,
                                  const std::optional<UrlMatchType>&)>
         url_match_predicate,
@@ -48,6 +49,7 @@
       transition_type(transition_type),
       should_warm_up_compositor(should_warm_up_compositor),
       should_prepare_paint_tree(should_prepare_paint_tree),
+      should_pause_javascript_execution(should_pause_javascript_execution),
       url_match_predicate(std::move(url_match_predicate)),
       prerender_navigation_handle_callback(
           std::move(prerender_navigation_handle_callback)),
diff --git a/content/browser/preloading/prerender/prerender_attributes.h b/content/browser/preloading/prerender/prerender_attributes.h
index 88d10db..776c2bf 100644
--- a/content/browser/preloading/prerender/prerender_attributes.h
+++ b/content/browser/preloading/prerender/prerender_attributes.h
@@ -50,6 +50,7 @@
       ui::PageTransition transition_type,
       bool should_warm_up_compositor,
       bool should_prepare_paint_tree,
+      bool should_pause_javascript_execution,
       base::RepeatingCallback<bool(const GURL&,
                                    const std::optional<UrlMatchType>&)>
           url_match_predicate,
@@ -127,6 +128,9 @@
   // then the intermediate result can be reused after activation.
   bool should_prepare_paint_tree = false;
 
+  // Whether to pause the renderer process's JavaScript execution.
+  bool should_pause_javascript_execution = false;
+
   // If the caller wants to override the default holdback processing, they can
   // set this. Otherwise, it will be computed as part of
   // PrerenderHostRegistry::CreateAndStartHost.
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index e43bb91..a7904a78 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -15363,7 +15363,13 @@
                                                             prerender_url);
   FrameTreeNodeId host_id =
       test::PrerenderTestHelper::GetHostForUrl(*web_contents(), prerender_url);
-  EXPECT_TRUE(host_id) << host_id;
+  ASSERT_TRUE(host_id);
+
+  PrerenderHost* prerender_host =
+      web_contents_impl()->GetPrerenderHostRegistry()->FindNonReservedHostById(
+          host_id);
+  ASSERT_TRUE(prerender_host);
+  EXPECT_TRUE(prerender_host->should_pause_javascript_execution());
 }
 
 }  // namespace content
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h
index 212e907..0d1b6b5 100644
--- a/content/browser/preloading/prerender/prerender_host.h
+++ b/content/browser/preloading/prerender/prerender_host.h
@@ -388,6 +388,10 @@
     return attributes_.should_prepare_paint_tree;
   }
 
+  bool should_pause_javascript_execution() const {
+    return attributes_.should_pause_javascript_execution;
+  }
+
   bool IsInitialNavigation(const NavigationRequest& navigation_request) const;
 
   bool were_headers_received() const { return were_headers_received_; }
diff --git a/content/browser/preloading/prerender/prerender_host_registry_unittest.cc b/content/browser/preloading/prerender/prerender_host_registry_unittest.cc
index 5fa79d7..c6ef21a 100644
--- a/content/browser/preloading/prerender/prerender_host_registry_unittest.cc
+++ b/content/browser/preloading/prerender/prerender_host_registry_unittest.cc
@@ -208,6 +208,7 @@
             ui::PAGE_TRANSITION_LINK,
             /*should_warm_up_compositor=*/false,
             /*should_prepare_paint_tree=*/false,
+            /*should_pause_javascript_execution=*/false,
             /*url_match_predicate=*/{},
             /*prerender_navigation_handle_callback=*/{},
             PreloadPipelineInfoImpl::Create(
@@ -223,6 +224,7 @@
                                       ui::PAGE_TRANSITION_FROM_ADDRESS_BAR),
             /*should_warm_up_compositor=*/false,
             /*should_prepare_paint_tree=*/false,
+            /*should_pause_javascript_execution=*/false,
             /*url_match_predicate=*/{},
             /*prerender_navigation_handle_callback=*/{},
             PreloadPipelineInfoImpl::Create(
diff --git a/content/browser/preloading/prerender/prerender_host_unittest.cc b/content/browser/preloading/prerender/prerender_host_unittest.cc
index 5112e69..64d27ff 100644
--- a/content/browser/preloading/prerender/prerender_host_unittest.cc
+++ b/content/browser/preloading/prerender/prerender_host_unittest.cc
@@ -281,7 +281,9 @@
         /*no_vary_search_hint=*/std::nullopt, rfh, contents()->GetWeakPtr(),
         ui::PAGE_TRANSITION_LINK,
         /*should_warm_up_compositor=*/false,
-        /*should_prepare_paint_tree=*/false, std::move(url_match_predicate),
+        /*should_prepare_paint_tree=*/false,
+        /*should_pause_javascript_execution=*/false,
+        std::move(url_match_predicate),
         /*prerender_navigation_handle_callback=*/{},
         PreloadPipelineInfoImpl::Create(
             /*planned_max_preloading_type=*/PreloadingType::kPrerender),
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index bfd547aa..724206b 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -45,6 +45,18 @@
   }
 }
 
+bool ShouldPauseJavaScriptExecution(blink::mojom::SpeculationAction action) {
+  switch (action) {
+    case blink::mojom::SpeculationAction::kPrerender:
+      return false;
+    case blink::mojom::SpeculationAction::kPrerenderUntilScript:
+      return true;
+    case blink::mojom::SpeculationAction::kPrefetch:
+    case blink::mojom::SpeculationAction::kPrefetchWithSubresources:
+      NOTREACHED();
+  }
+}
+
 }  // namespace
 
 struct PrerendererImpl::PrerenderInfo {
@@ -390,6 +402,7 @@
       web_contents->GetWeakPtr(), ui::PAGE_TRANSITION_LINK,
       should_warm_up_compositor,
       /*should_prepare_paint_tree=*/false,
+      ShouldPauseJavaScriptExecution(candidate->action),
       /*url_match_predicate=*/{},
       /*prerender_navigation_handle_callback=*/{},
       PreloadPipelineInfoImpl::Create(
diff --git a/content/browser/renderer_host/direct_manipulation_helper_win.cc b/content/browser/renderer_host/direct_manipulation_helper_win.cc
index 7849a7fc..51dac34 100644
--- a/content/browser/renderer_host/direct_manipulation_helper_win.cc
+++ b/content/browser/renderer_host/direct_manipulation_helper_win.cc
@@ -215,8 +215,11 @@
 }
 
 void DirectManipulationHelper::OnPointerHitTest(WPARAM w_param) {
+  if (!event_handler_) {
+    return;
+  }
+
   // Update the device scale factor.
-  DCHECK(event_handler_);
   event_handler_->SetDeviceScaleFactor(
       display::win::GetScreenWin()->GetScaleFactorForHWND(window_));
 
diff --git a/content/browser/renderer_host/mixed_content_checker.cc b/content/browser/renderer_host/mixed_content_checker.cc
index 477ddd1..583ad87 100644
--- a/content/browser/renderer_host/mixed_content_checker.cc
+++ b/content/browser/renderer_host/mixed_content_checker.cc
@@ -329,7 +329,7 @@
   // has given permission for the LNA request to go through.
   //
   // Reference:
-  // https://github.com/explainers-by-googlers/local-network-access
+  // https://wicg.github.io/local-network-access/
   //
   // This only checks for mixed content subframe navigations; subresource mixed
   // content is checked in
diff --git a/content/browser/renderer_host/navigation_throttle_registry_impl.cc b/content/browser/renderer_host/navigation_throttle_registry_impl.cc
index 7e95f619..63e9118 100644
--- a/content/browser/renderer_host/navigation_throttle_registry_impl.cc
+++ b/content/browser/renderer_host/navigation_throttle_registry_impl.cc
@@ -23,6 +23,7 @@
 #include "content/browser/renderer_host/mixed_content_navigation_throttle.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/browser/renderer_host/navigation_throttle_runner.h"
+#include "content/browser/renderer_host/navigation_throttle_runner2.h"
 #include "content/browser/renderer_host/navigator_delegate.h"
 #include "content/browser/renderer_host/partitioned_popins/partitioned_popins_navigation_throttle.h"
 #include "content/browser/renderer_host/renderer_cancellation_throttle.h"
@@ -36,12 +37,28 @@
 
 namespace content {
 
+namespace {
+
+std::unique_ptr<NavigationThrottleRunnerBase> CreateNavigationThrottleRunner(
+    NavigationThrottleRegistryBase* registry,
+    int64_t navigation_id,
+    bool is_primary_main_frame) {
+  if (base::FeatureList::IsEnabled(features::kNavigationThrottleRunner2)) {
+    return std::make_unique<NavigationThrottleRunner2>(registry, navigation_id,
+                                                       is_primary_main_frame);
+  }
+  return std::make_unique<NavigationThrottleRunner>(registry, navigation_id,
+                                                    is_primary_main_frame);
+}
+
+}  // namespace
+
 NavigationThrottleRegistryBase::~NavigationThrottleRegistryBase() = default;
 
 NavigationThrottleRegistryImpl::NavigationThrottleRegistryImpl(
     NavigationRequest* navigation_request)
     : navigation_request_(CHECK_DEREF(navigation_request)),
-      navigation_throttle_runner_(std::make_unique<NavigationThrottleRunner>(
+      navigation_throttle_runner_(CreateNavigationThrottleRunner(
           this,
           navigation_request->GetNavigationId(),
           navigation_request->IsInPrimaryMainFrame())) {}
diff --git a/content/browser/renderer_host/navigation_throttle_registry_impl.h b/content/browser/renderer_host/navigation_throttle_registry_impl.h
index e2f9825..9887ba1 100644
--- a/content/browser/renderer_host/navigation_throttle_registry_impl.h
+++ b/content/browser/renderer_host/navigation_throttle_registry_impl.h
@@ -40,6 +40,29 @@
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/navigation/enums.xml:NavigationThrottleEvent)
 
+// This is an abstract class that collaborates with
+// NavigationThrottleRegistryBase that owns the set of NavigationThrottles added
+// to an underlying navigation, and is responsible for calling the various sets
+// of events on its NavigationThrottles, and notifying its delegate about the
+// results of said events.
+class NavigationThrottleRunnerBase {
+ public:
+  virtual ~NavigationThrottleRunnerBase() = default;
+
+  // Will call the appropriate NavigationThrottle function based on `event` on
+  // all NavigationThrottles owned by this NavigationThrottleRunner.
+  virtual void ProcessNavigationEvent(NavigationThrottleEvent event) = 0;
+
+  // Resumes calling the appropriate NavigationThrottle functions for the
+  // current processing event on all NavigationThrottles that have not yet been
+  // notified.
+  // `resuming_throttle` is the NavigationThrottle that asks for navigation
+  // event processing to be resumed; it should be the one currently deferring
+  // the navigation.
+  virtual void ResumeProcessingNavigationEvent(
+      NavigationThrottle* resuming_throttle) = 0;
+};
+
 class CONTENT_EXPORT NavigationThrottleRegistryBase
     : public NavigationThrottleRegistry {
  public:
@@ -133,7 +156,7 @@
 
   // Owns the NavigationThrottles associated with this navigation, and is
   // responsible for notifying them about the various navigation events.
-  std::unique_ptr<NavigationThrottleRunner> navigation_throttle_runner_;
+  std::unique_ptr<NavigationThrottleRunnerBase> navigation_throttle_runner_;
 
   // A list of Throttles registered for this navigation.
   std::vector<std::unique_ptr<NavigationThrottle>> throttles_;
diff --git a/content/browser/renderer_host/navigation_throttle_runner.h b/content/browser/renderer_host/navigation_throttle_runner.h
index 4dd3988..d51f333b 100644
--- a/content/browser/renderer_host/navigation_throttle_runner.h
+++ b/content/browser/renderer_host/navigation_throttle_runner.h
@@ -10,7 +10,7 @@
 #include <optional>
 #include <vector>
 
-#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
 #include "base/memory/safety_checks.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
@@ -20,11 +20,13 @@
 
 namespace content {
 
-// This class collaborates with NavigationThrottleRegistry that owns the set of
-// NavigationThrottles added to an underlying navigation, and is responsible for
-// calling the various sets of events on its NavigationThrottles, and notifying
-// its delegate of the results of said events.
-class CONTENT_EXPORT NavigationThrottleRunner {
+// This is the original implementation of the NavigationThrottleRunner, and now
+// the essential interfaces are defined in the NavigationThrottleRunnerBase to
+// introduce an alternative runner, called NavigationThrottleRunner2, which will
+// eventually replace this class. See https://crbug.com/422003056 for more
+// information.
+class CONTENT_EXPORT NavigationThrottleRunner
+    : public NavigationThrottleRunnerBase {
   // Do not remove this macro!
   // The macro is maintained by the memory safety team.
   ADVANCED_MEMORY_SAFETY_CHECKS();
@@ -38,18 +40,12 @@
   NavigationThrottleRunner(const NavigationThrottleRunner&) = delete;
   NavigationThrottleRunner& operator=(const NavigationThrottleRunner&) = delete;
 
-  ~NavigationThrottleRunner();
+  ~NavigationThrottleRunner() override;
 
-  // Will call the appropriate NavigationThrottle function based on |event| on
-  // all NavigationThrottles owned by this NavigationThrottleRunner.
-  void ProcessNavigationEvent(NavigationThrottleEvent event);
-
-  // Resumes calling the appropriate NavigationThrottle functions for |event_|
-  // on all NavigationThrottles that have not yet been notified.
-  // |resuming_throttle| is the NavigationThrottle that asks for navigation
-  // event processing to be resumed; it should be the one currently deferring
-  // the navigation.
-  void ResumeProcessingNavigationEvent(NavigationThrottle* resuming_throttle);
+  // Implements NavigationThrottleRunnerBase:
+  void ProcessNavigationEvent(NavigationThrottleEvent event) override;
+  void ResumeProcessingNavigationEvent(
+      NavigationThrottle* resuming_throttle) override;
 
  private:
   void ProcessInternal();
diff --git a/content/browser/renderer_host/navigation_throttle_runner2.cc b/content/browser/renderer_host/navigation_throttle_runner2.cc
new file mode 100644
index 0000000..51ed4e8
--- /dev/null
+++ b/content/browser/renderer_host/navigation_throttle_runner2.cc
@@ -0,0 +1,31 @@
+// 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 "content/browser/renderer_host/navigation_throttle_runner2.h"
+
+namespace content {
+
+NavigationThrottleRunner2::NavigationThrottleRunner2(
+    NavigationThrottleRegistryBase* registry,
+    int64_t navigation_id,
+    bool is_primary_main_frame)
+    : registry_(*registry),
+      navigation_id_(navigation_id),
+      is_primary_main_frame_(is_primary_main_frame) {}
+
+NavigationThrottleRunner2::~NavigationThrottleRunner2() = default;
+
+void NavigationThrottleRunner2::ProcessNavigationEvent(
+    NavigationThrottleEvent event) {
+  // TODO(https://crbug.com/422003056): Implement this.
+  registry_->OnEventProcessed(event, NavigationThrottle::PROCEED);
+}
+
+void NavigationThrottleRunner2::ResumeProcessingNavigationEvent(
+    NavigationThrottle* resuming_throttle) {
+  // TODO(https://crbug.com/422003056): Implement this.
+  NOTREACHED();
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/navigation_throttle_runner2.h b/content/browser/renderer_host/navigation_throttle_runner2.h
new file mode 100644
index 0000000..c72aa86
--- /dev/null
+++ b/content/browser/renderer_host/navigation_throttle_runner2.h
@@ -0,0 +1,55 @@
+// 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 CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_RUNNER2_H_
+#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_RUNNER2_H_
+
+#include <stdint.h>
+
+#include "base/memory/raw_ref.h"
+#include "base/memory/safety_checks.h"
+#include "content/browser/renderer_host/navigation_throttle_registry_impl.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// This is a revamped implementation of the NavigationThrottleRunner that is
+// used behind a feature flag. See https://crbug.com/422003056 for more details.
+class CONTENT_EXPORT NavigationThrottleRunner2
+    : public NavigationThrottleRunnerBase {
+  // Do not remove this macro!
+  // The macro is maintained by the memory safety team.
+  ADVANCED_MEMORY_SAFETY_CHECKS();
+
+ public:
+  // `registry` should outlive this instance.
+  NavigationThrottleRunner2(NavigationThrottleRegistryBase* registry,
+                            int64_t navigation_id,
+                            bool is_primary_main_frame);
+
+  NavigationThrottleRunner2(const NavigationThrottleRunner2&) = delete;
+  NavigationThrottleRunner2& operator=(const NavigationThrottleRunner2&) =
+      delete;
+
+  ~NavigationThrottleRunner2() override;
+
+ private:
+  // Implements NavigationThrottleRunnerBase:
+  void ProcessNavigationEvent(NavigationThrottleEvent event) override;
+  void ResumeProcessingNavigationEvent(
+      NavigationThrottle* resuming_throttle) override;
+
+  const raw_ref<NavigationThrottleRegistryBase> registry_;
+
+  // The unique id of the navigation which this throttle runner is associated
+  // with.
+  const int64_t navigation_id_;
+
+  // Whether the navigation is in the primary main frame.
+  bool is_primary_main_frame_ = false;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_THROTTLE_RUNNER2_H_
diff --git a/content/browser/renderer_host/private_network_access_util.cc b/content/browser/renderer_host/private_network_access_util.cc
index b9590519..d3cfad1e 100644
--- a/content/browser/renderer_host/private_network_access_util.cc
+++ b/content/browser/renderer_host/private_network_access_util.cc
@@ -72,11 +72,7 @@
   if (local_network_access_checks_enabled) {
     // LNA blocks all local network access requests coming from non-secure
     // contexts.
-    // See:
-    // https://github.com/explainers-by-googlers/local-network-access?tab=readme-ov-file#integration-with-fetch
-    //
-    // TODO(crbug.com/395895368): figure out how this interacts with https
-    // upgrades.
+    // See: https://wicg.github.io/local-network-access/
     return network::features::kLocalNetworkAccessChecksWarn.Get()
                ? Policy::kPermissionWarn
                : Policy::kBlock;
@@ -119,8 +115,7 @@
 Policy DerivePolicyForSecureContext(AddressSpace ip_address_space,
                                     bool local_network_access_checks_enabled) {
   if (local_network_access_checks_enabled) {
-    // See:
-    // https://github.com/explainers-by-googlers/local-network-access?tab=readme-ov-file#permission-prompts
+    // See: https://wicg.github.io/local-network-access/
     return network::features::kLocalNetworkAccessChecksWarn.Get()
                ? Policy::kPermissionWarn
                : Policy::kPermissionBlock;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 2406cb3a..e44ece8 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -457,8 +457,10 @@
 
 using TokenFrameMap =
     absl::flat_hash_map<blink::LocalFrameToken, RenderFrameHostImpl*>;
-base::LazyInstance<TokenFrameMap>::Leaky g_token_frame_map =
-    LAZY_INSTANCE_INITIALIZER;
+TokenFrameMap& GetTokenFrameMap() {
+  static base::NoDestructor<TokenFrameMap> token_frame_map;
+  return *token_frame_map;
+}
 
 BackForwardCacheMetrics::NotRestoredReason
 RendererEvictionReasonToNotRestoredReason(
@@ -562,12 +564,12 @@
     int process_id,
     const blink::FrameToken& frame_token) {
   if (frame_token.Is<blink::LocalFrameToken>()) {
-    auto it = g_token_frame_map.Get().find(
-        frame_token.GetAs<blink::LocalFrameToken>());
+    auto it =
+        GetTokenFrameMap().find(frame_token.GetAs<blink::LocalFrameToken>());
     // The check against |process_id| isn't strictly necessary, but represents
     // an extra level of protection against a renderer trying to force a frame
     // token.
-    if (it == g_token_frame_map.Get().end() ||
+    if (it == GetTokenFrameMap().end() ||
         process_id != it->second->GetProcess()->GetDeprecatedID()) {
       return RenderFrameHostOrProxy(nullptr, nullptr);
     }
@@ -2120,9 +2122,10 @@
     const blink::LocalFrameToken& frame_token,
     mojo::ReportBadMessageCallback* process_mismatch_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  auto it = g_token_frame_map.Get().find(frame_token);
-  if (it == g_token_frame_map.Get().end())
+  auto it = GetTokenFrameMap().find(frame_token);
+  if (it == GetTokenFrameMap().end()) {
     return nullptr;
+  }
 
   if (it->second->GetProcess()->GetDeprecatedID() != process_id) {
     if (process_mismatch_callback) {
@@ -2181,8 +2184,8 @@
 RenderFrameHostImpl* RenderFrameHostImpl::FromOverlayRoutingToken(
     const base::UnguessableToken& token) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  auto it = g_token_frame_map.Get().find(blink::LocalFrameToken(token));
-  return it == g_token_frame_map.Get().end() ? nullptr : it->second;
+  auto it = GetTokenFrameMap().find(blink::LocalFrameToken(token));
+  return it == GetTokenFrameMap().end() ? nullptr : it->second;
 }
 
 // static
@@ -2437,7 +2440,7 @@
   g_routing_id_frame_map.Get().emplace(
       GlobalRenderFrameHostId(GetProcess()->GetDeprecatedID(), routing_id_),
       this);
-  g_token_frame_map.Get().insert(std::make_pair(frame_token_, this));
+  GetTokenFrameMap().insert(std::make_pair(frame_token_, this));
   site_instance_->group()->AddObserver(this);
   auto* process = GetProcess();
   process->RegisterRenderFrameHost(GetGlobalId(), IsOutermostMainFrame());
@@ -2684,7 +2687,7 @@
         GetNetworkIsolationKey());
   }
 
-  g_token_frame_map.Get().erase(frame_token_);
+  GetTokenFrameMap().erase(frame_token_);
 
   // Ensure that the render process host has been notified that all media
   // streams from this frame have terminated. This is required to ensure the
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc
index fb75d59..e31af1e 100644
--- a/content/browser/renderer_host/render_frame_proxy_host.cc
+++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -70,8 +70,10 @@
 
 using TokenFrameMap =
     absl::flat_hash_map<blink::RemoteFrameToken, RenderFrameProxyHost*>;
-base::LazyInstance<TokenFrameMap>::Leaky g_token_frame_proxy_map =
-    LAZY_INSTANCE_INITIALIZER;
+TokenFrameMap& GetTokenFrameProxyMap() {
+  static base::NoDestructor<TokenFrameMap> token_frame_proxy_map;
+  return *token_frame_proxy_map;
+}
 
 // TODO(https://crbug.com/339512240): Remove this killswitch once the
 // optimization for postMessage proxy creation finishes rolling out.
@@ -102,7 +104,7 @@
     int process_id,
     const blink::RemoteFrameToken& frame_token) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  TokenFrameMap* frames = g_token_frame_proxy_map.Pointer();
+  TokenFrameMap* frames = &GetTokenFrameProxyMap();
   auto it = frames->find(frame_token);
   // The check against |process_id| isn't strictly necessary, but represents
   // an extra level of protection against a renderer trying to force a frame
@@ -117,7 +119,7 @@
 bool RenderFrameProxyHost::IsFrameTokenInUse(
     const blink::RemoteFrameToken& frame_token) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  TokenFrameMap* frames = g_token_frame_proxy_map.Pointer();
+  TokenFrameMap* frames = &GetTokenFrameProxyMap();
   return frames->find(frame_token) != frames->end();
 }
 
@@ -143,7 +145,7 @@
                                        routing_id_),
                 this))
             .second);
-  CHECK(g_token_frame_proxy_map.Get()
+  CHECK(GetTokenFrameProxyMap()
             .insert(std::make_pair(frame_token_, this))
             .second);
   CHECK(render_view_host_ ||
@@ -196,7 +198,7 @@
   GetAgentSchedulingGroup().RemoveRoute(routing_id_);
   g_routing_id_frame_proxy_map.Get().erase(
       RenderFrameProxyHostID(GetProcess()->GetDeprecatedID(), routing_id_));
-  g_token_frame_proxy_map.Get().erase(frame_token_);
+  GetTokenFrameProxyMap().erase(frame_token_);
   TRACE_EVENT_END("navigation.debug", perfetto::Track::FromPointer(this));
 }
 
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 04f7f6c..595e637 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -23,6 +23,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/no_destructor.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -127,8 +128,10 @@
 using RenderViewHostID = std::pair<int32_t, int32_t>;
 using RoutingIDViewMap =
     absl::flat_hash_map<RenderViewHostID, RenderViewHostImpl*>;
-base::LazyInstance<RoutingIDViewMap>::Leaky g_routing_id_view_map =
-    LAZY_INSTANCE_INITIALIZER;
+RoutingIDViewMap& GetRoutingIDViewMap() {
+  static base::NoDestructor<RoutingIDViewMap> routing_id_view_map;
+  return *routing_id_view_map;
+}
 
 #if BUILDFLAG(IS_WIN)
 // Fetches the name and font size of a particular Windows system font.
@@ -228,9 +231,9 @@
 // static
 RenderViewHostImpl* RenderViewHostImpl::FromID(int process_id, int routing_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  RoutingIDViewMap* views = g_routing_id_view_map.Pointer();
-  auto it = views->find(RenderViewHostID(process_id, routing_id));
-  return it == views->end() ? nullptr : it->second;
+  RoutingIDViewMap& views = GetRoutingIDViewMap();
+  auto it = views.find(RenderViewHostID(process_id, routing_id));
+  return it == views.end() ? nullptr : it->second;
 }
 
 // static
@@ -339,7 +342,7 @@
       ->Insert(this);
 
   std::pair<RoutingIDViewMap::iterator, bool> result =
-      g_routing_id_view_map.Get().emplace(
+      GetRoutingIDViewMap().emplace(
           RenderViewHostID(GetProcess()->GetDeprecatedID(), routing_id_), this);
   CHECK(result.second) << "Inserting a duplicate item!";
   GetAgentSchedulingGroup().AddRoute(routing_id_, this);
@@ -378,7 +381,7 @@
 
   // Detach the routing ID as the object is going away.
   GetAgentSchedulingGroup().RemoveRoute(GetRoutingID());
-  g_routing_id_view_map.Get().erase(
+  GetRoutingIDViewMap().erase(
       RenderViewHostID(GetProcess()->GetDeprecatedID(), GetRoutingID()));
 
   delegate_->RenderViewDeleted(this);
@@ -469,10 +472,13 @@
           prerender_host.should_warm_up_compositor();
       prerender_param->should_prepare_paint_tree =
           prerender_host.should_prepare_paint_tree();
+      prerender_param->should_pause_javascript_execution =
+          prerender_host.should_pause_javascript_execution();
     } else {
       prerender_param->page_metric_suffix = ".Preview";
       prerender_param->should_warm_up_compositor = false;
       prerender_param->should_prepare_paint_tree = false;
+      prerender_param->should_pause_javascript_execution = false;
     }
     params->prerender_param = std::move(prerender_param);
   }
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 1f93be24..f02b036 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -73,7 +73,6 @@
 #include "content/test/frame_host_interceptor.h"
 #include "content/test/test_content_browser_client.h"
 #include "ipc/constants.mojom.h"
-#include "ipc/ipc_security_test_util.h"
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -111,7 +110,6 @@
 #include "third_party/blink/public/mojom/frame/remote_frame.mojom-test-utils.h"
 #include "third_party/blink/public/mojom/loader/mixed_content.mojom.h"
 
-using IPC::IpcSecurityTestUtil;
 using ::testing::HasSubstr;
 using ::testing::Optional;
 
diff --git a/content/browser/service_host/utility_process_sandbox_browsertest.cc b/content/browser/service_host/utility_process_sandbox_browsertest.cc
index a94e84e..4cd6afd 100644
--- a/content/browser/service_host/utility_process_sandbox_browsertest.cc
+++ b/content/browser/service_host/utility_process_sandbox_browsertest.cc
@@ -122,7 +122,6 @@
 
       case Sandbox::kAudio:
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-      case Sandbox::kShapeDetection:
 #if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
       case Sandbox::kHardwareVideoDecoding:
 #endif  // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
@@ -134,6 +133,7 @@
       case Sandbox::kIme:
       case Sandbox::kTts:
       case Sandbox::kNearby:
+      case Sandbox::kShapeDetection:
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
       case Sandbox::kLibassistant:
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
diff --git a/content/browser/service_host/utility_sandbox_delegate.cc b/content/browser/service_host/utility_sandbox_delegate.cc
index 8f89c28..ff9941f 100644
--- a/content/browser/service_host/utility_sandbox_delegate.cc
+++ b/content/browser/service_host/utility_sandbox_delegate.cc
@@ -80,7 +80,6 @@
       sandbox_type_ == sandbox::mojom::Sandbox::kVideoCapture ||
 #endif
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-      sandbox_type_ == sandbox::mojom::Sandbox::kShapeDetection ||
 #if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
       sandbox_type_ == sandbox::mojom::Sandbox::kHardwareVideoDecoding ||
 #endif  // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
@@ -92,6 +91,7 @@
       sandbox_type_ == sandbox::mojom::Sandbox::kIme ||
       sandbox_type_ == sandbox::mojom::Sandbox::kTts ||
       sandbox_type_ == sandbox::mojom::Sandbox::kNearby ||
+      sandbox_type_ == sandbox::mojom::Sandbox::kShapeDetection ||
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
       sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant ||
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
@@ -159,14 +159,12 @@
       sandbox_type_ == sandbox::mojom::Sandbox::kIme ||
       sandbox_type_ == sandbox::mojom::Sandbox::kTts ||
       sandbox_type_ == sandbox::mojom::Sandbox::kNearby ||
+      sandbox_type_ == sandbox::mojom::Sandbox::kShapeDetection ||
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
       sandbox_type_ == sandbox::mojom::Sandbox::kLibassistant ||
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
 #endif  // BUILDFLAG(IS_CHROMEOS)
       sandbox_type_ == sandbox::mojom::Sandbox::kAudio ||
-#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
-      sandbox_type_ == sandbox::mojom::Sandbox::kShapeDetection ||
-#endif
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
     BUILDFLAG(IS_WIN)
       sandbox_type_ == sandbox::mojom::Sandbox::kPrintBackend ||
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 4645ecf..bce4280 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -11,7 +11,7 @@
 #include "base/containers/contains.h"
 #include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
-#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
 #include "base/notreached.h"
 #include "base/trace_event/typed_macros.h"
 #include "content/browser/bad_message.h"
@@ -85,10 +85,8 @@
   struct DefaultSiteURL {
     const GURL url = GURL("http://unisolated.invalid");
   };
-  static base::LazyInstance<DefaultSiteURL>::Leaky default_site_url =
-      LAZY_INSTANCE_INITIALIZER;
-
-  return default_site_url.Get().url;
+  static base::NoDestructor<DefaultSiteURL> default_site_url;
+  return default_site_url->url;
 }
 
 class SiteInstanceImpl::DefaultSiteInstanceState {
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index e336594..096bf5be 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -134,7 +134,6 @@
 #include "content/test/did_commit_navigation_interceptor.h"
 #include "content/test/render_document_feature.h"
 #include "ipc/constants.mojom.h"
-#include "ipc/ipc_security_test_util.h"
 #include "media/base/media_switches.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/sync_call_restrictions.h"
diff --git a/content/browser/wake_lock/wake_lock_context_host.cc b/content/browser/wake_lock/wake_lock_context_host.cc
index 10503fd..3fa649775 100644
--- a/content/browser/wake_lock/wake_lock_context_host.cc
+++ b/content/browser/wake_lock/wake_lock_context_host.cc
@@ -5,7 +5,7 @@
 #include "content/browser/wake_lock/wake_lock_context_host.h"
 
 #include "base/atomic_sequence_num.h"
-#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
 #include "content/public/browser/device_service.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/wake_lock_provider.mojom.h"
@@ -16,19 +16,22 @@
 
 base::AtomicSequenceNumber g_unique_id;
 
-base::LazyInstance<std::map<int, WakeLockContextHost*>>::Leaky
-    g_id_to_context_host = LAZY_INSTANCE_INITIALIZER;
+std::map<int, WakeLockContextHost*>& GetIdToContextHostMap() {
+  static base::NoDestructor<std::map<int, WakeLockContextHost*>>
+      id_to_context_host;
+  return *id_to_context_host;
+}
 
 WakeLockContextHost* ContextHostFromId(int id) {
-  auto it = g_id_to_context_host.Get().find(id);
-  return it != g_id_to_context_host.Get().end() ? it->second : nullptr;
+  auto it = GetIdToContextHostMap().find(id);
+  return it != GetIdToContextHostMap().end() ? it->second : nullptr;
 }
 
 }  // namespace
 
 WakeLockContextHost::WakeLockContextHost(WebContents* web_contents)
     : id_(g_unique_id.GetNext()), web_contents_(web_contents) {
-  g_id_to_context_host.Get()[id_] = this;
+  GetIdToContextHostMap()[id_] = this;
 
   // Connect to a WakeLockContext, associating it with |id_|.
   mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider;
@@ -39,7 +42,7 @@
 }
 
 WakeLockContextHost::~WakeLockContextHost() {
-  g_id_to_context_host.Get().erase(id_);
+  GetIdToContextHostMap().erase(id_);
 }
 
 // static
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index ebfc82c..6e468ab 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -12038,6 +12038,7 @@
       no_vary_search_hint,
       /*initiator_render_frame_host=*/nullptr, GetWeakPtr(), page_transition,
       should_warm_up_compositor, should_prepare_paint_tree,
+      /*should_pause_javascript_execution=*/false,
       std::move(url_match_predicate),
       std::move(prerender_navigation_handle_callback),
       base::WrapRefCounted(
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 3ef2f9a..56b8225 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -138,7 +138,7 @@
 #if BUILDFLAG(IS_MAC)
 #include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/mac/authenticator_config.h"
 #include "device/fido/mac/credential_store.h"
 #include "device/fido/mac/icloud_keychain.h"
@@ -9530,7 +9530,7 @@
   // Disable biometrics to verify that requests without uv required do not
   // prompt the user for their macOS password.
   touch_id_test_environment_.keychain()->SetUVMethod(
-      crypto::ScopedFakeAppleKeychainV2::UVMethod::kPasswordOnly);
+      crypto::apple::ScopedFakeKeychainV2::UVMethod::kPasswordOnly);
   for (const auto uv : {device::UserVerificationRequirement::kDiscouraged,
                         device::UserVerificationRequirement::kPreferred,
                         device::UserVerificationRequirement::kRequired}) {
diff --git a/content/browser/webid/digital_credentials/digital_identity_request_impl.cc b/content/browser/webid/digital_credentials/digital_identity_request_impl.cc
index 675535eb..4e18e90 100644
--- a/content/browser/webid/digital_credentials/digital_identity_request_impl.cc
+++ b/content/browser/webid/digital_credentials/digital_identity_request_impl.cc
@@ -408,9 +408,9 @@
     // absent, the protocol specified in the original request will be used
     // instead. This fallback mechanism maintains backward compatibility with
     // digital wallets that do not include the protocol in their response.
-    std::move(callback_).Run(status,
-                             response->protocol.value_or(protocol.value()),
-                             std::move(response->data));
+    std::move(callback_).Run(
+        status, response->protocol.has_value() ? response->protocol : protocol,
+        std::move(response->data));
   } else {
     std::move(callback_).Run(status, std::nullopt, std::nullopt);
   }
diff --git a/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc b/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc
index ea81758e..0f7a9402 100644
--- a/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc
+++ b/content/browser/webid/digital_credentials/digital_identity_request_impl_unittest.cc
@@ -1090,6 +1090,53 @@
 }
 
 TEST_F(DigitalIdentityRequestImplTest,
+       ShouldGetWhenMultipleRequestsAndReturnProtocolInResponse) {
+  const Value kResponseData(Value::Dict().Set("token", "token data"));
+  const std::string kProtocolInResponse = "protocol1";
+  std::vector<DigitalCredentialGetRequestPtr> requests;
+
+  DigitalCredentialGetRequestPtr request1 = DigitalCredentialGetRequest::New();
+  request1->protocol = "protocol1";
+  base::Value::Dict request1_data;
+  request1_data.Set("data", "request1 data");
+  request1->data = base::Value(std::move(request1_data));
+
+  DigitalCredentialGetRequestPtr request2 = DigitalCredentialGetRequest::New();
+  request2->protocol = "protocol2";
+  base::Value::Dict request2_data;
+  request2_data.Set("data", "request2 data");
+  request2->data = base::Value(std::move(request2_data));
+
+  requests.push_back(std::move(request1));
+  requests.push_back(std::move(request2));
+
+  base::RunLoop run_loop;
+
+  // Simulate a provider that returns a response without a protocol.
+  EXPECT_CALL(*mock_digital_identity_provider(), Get)
+      .WillOnce(WithArg<3>([this, &kProtocolInResponse,
+                            &kResponseData](DigitalIdentityCallback callback) {
+        // Running the `callback` will destroy the provider, reset the
+        // pointer to avoid dangling pointers after invoking the callback.
+        reset_provider_pointer();
+
+        std::move(callback).Run(
+            DigitalCredential(kProtocolInResponse, kResponseData.Clone()));
+      }));
+
+  base::MockCallback<GetCallback> mock_callback;
+  // The protocol in the response should be used when invoking the callback.
+  EXPECT_CALL(mock_callback, Run(RequestDigitalIdentityStatus::kSuccess,
+                                 Optional(kProtocolInResponse), _))
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
+
+  digital_identity_request_impl()->Get(std::move(requests),
+                                       mock_callback.Get());
+
+  run_loop.Run();
+}
+
+TEST_F(DigitalIdentityRequestImplTest,
        ShouldErrorWhenMultipleRequestsAndNoProtocolInResponse) {
   const Value kResponseData(Value::Dict().Set("token", "token data"));
 
diff --git a/content/browser/webui/url_data_manager.cc b/content/browser/webui/url_data_manager.cc
index 8275b55..418ab09 100644
--- a/content/browser/webui/url_data_manager.cc
+++ b/content/browser/webui/url_data_manager.cc
@@ -12,8 +12,8 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "base/lazy_instance.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/no_destructor.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
@@ -32,7 +32,10 @@
 
 const char kURLDataManagerKeyName[] = "url_data_manager";
 
-base::LazyInstance<base::Lock>::Leaky g_delete_lock = LAZY_INSTANCE_INITIALIZER;
+base::Lock& GetDeleteLock() {
+  static base::NoDestructor<base::Lock> delete_lock;
+  return *delete_lock;
+}
 
 URLDataManager* GetFromBrowserContext(BrowserContext* context) {
   if (!context->GetUserData(kURLDataManagerKeyName)) {
@@ -47,7 +50,7 @@
 
 // static
 URLDataManager::URLDataSources* URLDataManager::data_sources_ PT_GUARDED_BY(
-    g_delete_lock.Get()) = nullptr;
+    GetDeleteLock()) = nullptr;
 
 URLDataManager::URLDataManager(BrowserContext* browser_context)
     : browser_context_(browser_context) {
@@ -73,7 +76,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   URLDataSources sources;
   {
-    base::AutoLock lock(g_delete_lock.Get());
+    base::AutoLock lock(GetDeleteLock());
     if (!data_sources_)
       return;
     data_sources_->swap(sources);
@@ -95,7 +98,7 @@
   // to delete.
   bool schedule_delete = false;
   {
-    base::AutoLock lock(g_delete_lock.Get());
+    base::AutoLock lock(GetDeleteLock());
     if (!data_sources_)
       data_sources_ = new URLDataSources();
     schedule_delete = data_sources_->empty();
@@ -134,7 +137,7 @@
 // static
 bool URLDataManager::IsScheduledForDeletion(
     const URLDataSourceImpl* data_source) {
-  base::AutoLock lock(g_delete_lock.Get());
+  base::AutoLock lock(GetDeleteLock());
   return data_sources_ && base::Contains(*data_sources_, data_source);
 }
 
diff --git a/content/child/font_warmup_win.cc b/content/child/font_warmup_win.cc
index 1cbdba1..b01fc8b 100644
--- a/content/child/font_warmup_win.cc
+++ b/content/child/font_warmup_win.cc
@@ -13,7 +13,6 @@
 
 #include "base/debug/alias.h"
 #include "base/files/file_path.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
@@ -188,8 +187,10 @@
   base::Lock objects_lock_;
 };
 
-base::LazyInstance<FakeGdiObjectFactory>::Leaky g_fake_gdi_object_factory =
-    LAZY_INSTANCE_INITIALIZER;
+FakeGdiObjectFactory& GetFakeGdiObjectFactory() {
+  static base::NoDestructor<FakeGdiObjectFactory> fake_gdi_object_factory;
+  return *fake_gdi_object_factory;
+}
 
 // Magic values for the fake GDI objects.
 const uint32_t kFakeDCMagic = 'fkdc';
@@ -212,7 +213,7 @@
 
 HDC WINAPI CreateCompatibleDCPatch(HDC dc_handle) {
   scoped_refptr<FakeGdiObject> ret =
-      g_fake_gdi_object_factory.Get().Create(kFakeDCMagic);
+      GetFakeGdiObjectFactory().Create(kFakeDCMagic);
   return static_cast<HDC>(ret->handle());
 }
 
@@ -225,19 +226,18 @@
     return nullptr;
 
   scoped_refptr<FakeGdiObject> ret =
-      g_fake_gdi_object_factory.Get().Create(kFakeFontMagic);
+      GetFakeGdiObjectFactory().Create(kFakeFontMagic);
   ret->set_typeface(std::move(typeface));
 
   return static_cast<HFONT>(ret->handle());
 }
 
 BOOL WINAPI DeleteDCPatch(HDC dc_handle) {
-  return g_fake_gdi_object_factory.Get().DeleteObject(dc_handle, kFakeDCMagic);
+  return GetFakeGdiObjectFactory().DeleteObject(dc_handle, kFakeDCMagic);
 }
 
 BOOL WINAPI DeleteObjectPatch(HGDIOBJ object_handle) {
-  return g_fake_gdi_object_factory.Get().DeleteObject(object_handle,
-                                                      kFakeFontMagic);
+  return GetFakeGdiObjectFactory().DeleteObject(object_handle, kFakeFontMagic);
 }
 
 int WINAPI EnumFontFamiliesExWPatch(HDC dc_handle,
@@ -246,7 +246,7 @@
                                     LPARAM callback_param,
                                     DWORD flags) {
   scoped_refptr<FakeGdiObject> dc_obj =
-      g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic);
+      GetFakeGdiObjectFactory().Validate(dc_handle, kFakeDCMagic);
   if (!dc_obj)
     return 1;
 
@@ -275,7 +275,7 @@
                               LPVOID buffer,
                               DWORD buffer_length) {
   scoped_refptr<FakeGdiObject> dc_obj =
-      g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic);
+      GetFakeGdiObjectFactory().Validate(dc_handle, kFakeDCMagic);
   if (!dc_obj)
     return GDI_ERROR;
 
@@ -302,12 +302,12 @@
 
 HGDIOBJ WINAPI SelectObjectPatch(HDC dc_handle, HGDIOBJ object_handle) {
   scoped_refptr<FakeGdiObject> dc_obj =
-      g_fake_gdi_object_factory.Get().Validate(dc_handle, kFakeDCMagic);
+      GetFakeGdiObjectFactory().Validate(dc_handle, kFakeDCMagic);
   if (!dc_obj)
     return nullptr;
 
   scoped_refptr<FakeGdiObject> font_obj =
-      g_fake_gdi_object_factory.Get().Validate(object_handle, kFakeFontMagic);
+      GetFakeGdiObjectFactory().Validate(object_handle, kFakeFontMagic);
   if (!font_obj)
     return nullptr;
 
@@ -315,7 +315,7 @@
   scoped_refptr<FakeGdiObject> new_font_obj;
   sk_sp<SkTypeface> old_typeface = dc_obj->typeface();
   if (old_typeface) {
-    new_font_obj = g_fake_gdi_object_factory.Get().Create(kFakeFontMagic);
+    new_font_obj = GetFakeGdiObjectFactory().Create(kFakeFontMagic);
     new_font_obj->set_typeface(std::move(old_typeface));
   }
   dc_obj->set_typeface(font_obj->typeface());
@@ -425,11 +425,11 @@
 }
 
 size_t GetEmulatedGdiHandleCountForTesting() {
-  return g_fake_gdi_object_factory.Get().GetObjectCount();
+  return GetFakeGdiObjectFactory().GetObjectCount();
 }
 
 void ResetEmulatedGdiHandlesForTesting() {
-  g_fake_gdi_object_factory.Get().ResetObjectHandles();
+  GetFakeGdiObjectFactory().ResetObjectHandles();
 }
 
 void SetPreSandboxWarmupFontMgrForTesting(sk_sp<SkFontMgr> fontmgr) {
diff --git a/content/common/features.cc b/content/common/features.cc
index c216266f..2c2e441 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -362,6 +362,12 @@
              "NavigationThrottleRegistryAttributeCache",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// When enabled, NavigationThrottleRunner2 is used instead of the original
+// NavigationThrottleRunner. See https://crbug.com/422003056.
+BASE_FEATURE(kNavigationThrottleRunner2,
+             "NavigationThrottleRunner2",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // This feature enables Permissions Policy verification in the Browser process
 // in content/. Additionally only for //chrome Permissions Policy verification
 // is enabled in components/permissions/permission_context_base.cc
diff --git a/content/common/features.h b/content/common/features.h
index 7913d0e..6e56b5cf 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -108,6 +108,7 @@
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kMultipleSpareRPHs);
 CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(size_t, kMultipleSpareRPHsCount);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kNavigationThrottleRegistryAttributeCache);
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kNavigationThrottleRunner2);
 #if !BUILDFLAG(IS_ANDROID)
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kPermissionsPolicyVerificationInContent);
 #endif
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentUiEventHandler.java b/content/public/android/java/src/org/chromium/content/browser/ContentUiEventHandler.java
index 1068fa1..872ec87 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentUiEventHandler.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentUiEventHandler.java
@@ -105,11 +105,7 @@
                 .sendMouseWheelEvent(
                         mNativeContentUiEventHandler,
                         event,
-                        MotionEventUtils.getEventTimeNanos(event),
-                        event.getX(),
-                        event.getY(),
-                        event.getAxisValue(MotionEvent.AXIS_HSCROLL),
-                        event.getAxisValue(MotionEvent.AXIS_VSCROLL));
+                        MotionEventUtils.getEventTimeNanos(event));
     }
 
     private boolean onMouseEvent(MotionEvent event, boolean shouldConvertToMouseEvent) {
@@ -126,15 +122,7 @@
                         mNativeContentUiEventHandler,
                         event,
                         MotionEventUtils.getEventTimeNanos(event),
-                        event.getActionMasked(),
-                        event.getX(),
-                        event.getY(),
-                        event.getPointerId(0),
-                        event.getPressure(0),
-                        event.getOrientation(0),
-                        event.getAxisValue(MotionEvent.AXIS_TILT, 0),
                         EventForwarder.getMouseEventActionButton(event),
-                        event.getButtonState(),
                         shouldConvertToMouseEvent
                                 ? MotionEvent.TOOL_TYPE_MOUSE
                                 : event.getToolType(0));
@@ -229,28 +217,13 @@
     interface Natives {
         long init(ContentUiEventHandler self, WebContents webContents);
 
-        void sendMouseWheelEvent(
-                long nativeContentUiEventHandler,
-                MotionEvent event,
-                long timeNs,
-                float x,
-                float y,
-                float ticksX,
-                float ticksY);
+        void sendMouseWheelEvent(long nativeContentUiEventHandler, MotionEvent event, long timeNs);
 
         void sendMouseEvent(
                 long nativeContentUiEventHandler,
                 MotionEvent event,
                 long timeNs,
-                int action,
-                float x,
-                float y,
-                int pointerId,
-                float pressure,
-                float orientation,
-                float tilt,
                 int changedButton,
-                int buttonState,
                 int toolType);
 
         void sendScrollEvent(
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java b/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
index 61e00d8..ffe0d68 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/MediaSession.java
@@ -6,7 +6,6 @@
 
 import org.chromium.base.ObserverList;
 import org.chromium.build.annotations.NullMarked;
-import org.chromium.build.annotations.Nullable;
 import org.chromium.content.browser.MediaSessionImpl;
 
 /** The MediaSession Java wrapper to allow communicating with the native MediaSession object. */
@@ -15,7 +14,7 @@
     /**
      * @return The MediaSession associated with |contents|.
      */
-    public static @Nullable MediaSession fromWebContents(WebContents contents) {
+    public static MediaSession fromWebContents(WebContents contents) {
         // TODO(zqzhang): directly call WebContentsImpl.getMediaSession() when WebContentsImpl
         // package restriction is removed.
         return MediaSessionImpl.fromWebContents(contents);
diff --git a/content/public/android/junit/src/org/chromium/content/browser/ContentUiEventHandlerTest.java b/content/public/android/junit/src/org/chromium/content/browser/ContentUiEventHandlerTest.java
index 60d51dd..c4360fc0 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/ContentUiEventHandlerTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/ContentUiEventHandlerTest.java
@@ -9,6 +9,7 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -86,31 +87,21 @@
     public void testOnGenericMotionEventSendsTrackpadClicksToNative() {
         MotionEvent trackpadLeftClickEvent = getTrackpadLeftClickEvent();
         mContentUiEventHandler.onGenericMotionEvent(getTrackpadLeftClickEvent());
-        verifySendMouseEvent(trackpadLeftClickEvent);
 
         MotionEvent trackpadRightClickEvent = getTrackRightClickEvent();
         mContentUiEventHandler.onGenericMotionEvent(getTrackRightClickEvent());
-        verifySendMouseEvent(trackpadRightClickEvent);
-    }
 
-    private void verifySendMouseEvent(MotionEvent event) {
         ArgumentCaptor<MotionEvent> captor = ArgumentCaptor.forClass(MotionEvent.class);
-        verify(mContentUiEventHandlerJniMock)
+        verify(mContentUiEventHandlerJniMock, times(2))
                 .sendMouseEvent(
                         eq(NATIVE_CONTENT_UI_EVENT_HANDLER),
                         captor.capture(),
-                        eq(MotionEventUtils.getEventTimeNanos(event)),
-                        eq(event.getActionMasked()),
-                        eq(event.getX()),
-                        eq(event.getY()),
-                        eq(event.getPointerId(0)),
-                        eq(event.getPressure(0)),
-                        eq(event.getOrientation(0)),
-                        eq(event.getAxisValue(MotionEvent.AXIS_TILT, 0)),
-                        eq(EventForwarder.getMouseEventActionButton(event)),
-                        eq(event.getButtonState()),
+                        eq(MotionEventUtils.getEventTimeNanos(trackpadLeftClickEvent)),
+                        eq(EventForwarder.getMouseEventActionButton(trackpadLeftClickEvent)),
                         eq(MotionEvent.TOOL_TYPE_MOUSE));
-        MotionEventTestUtils.assertEquals(captor.getValue(), event);
+
+        MotionEventTestUtils.assertEquals(captor.getAllValues().get(0), trackpadLeftClickEvent);
+        MotionEventTestUtils.assertEquals(captor.getAllValues().get(1), trackpadRightClickEvent);
     }
 
     private static MotionEvent getTrackpadLeftClickEvent() {
diff --git a/content/public/browser/media_session.h b/content/public/browser/media_session.h
index 9bc4686..e171ade 100644
--- a/content/public/browser/media_session.h
+++ b/content/public/browser/media_session.h
@@ -78,6 +78,17 @@
   // service, if the routed service exists, nullptr otherwise.
   virtual RenderFrameHost* GetRoutedFrame() = 0;
 
+  // Returns the current media session info synchronously for a one-off request.
+  virtual media_session::mojom::MediaSessionInfoPtr
+  GetMediaSessionInfoSync() = 0;
+
+  // Returns the current media session position for a one-off request.
+  virtual std::optional<media_session::MediaPosition>
+  GetMediaSessionPosition() = 0;
+
+  // Returns the current media session metadata for a one-off request.
+  virtual const media_session::MediaMetadata& GetMediaSessionMetadata() = 0;
+
   // Report to all players that information related to automatic picture in
   // picture has changed.
   virtual void ReportAutoPictureInPictureInfoChanged() = 0;
diff --git a/content/public/browser/web_ui_controller.cc b/content/public/browser/web_ui_controller.cc
index e6a2a19c..83501b0 100644
--- a/content/public/browser/web_ui_controller.cc
+++ b/content/public/browser/web_ui_controller.cc
@@ -4,6 +4,7 @@
 
 #include "content/public/browser/web_ui_controller.h"
 
+#include "base/no_destructor.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/webui/web_ui_managed_interface.h"
 #include "content/public/browser/web_ui_browser_interface_broker_registry.h"
@@ -17,8 +18,10 @@
 // with interfaces exposed to MojoJS. If such a mapping exists, we instantiate
 // the broker in ReadyToCommitNavigation, enable MojoJS bindings for this
 // frame, and ask renderer to use it to handle Mojo.bindInterface calls.
-base::LazyInstance<WebUIBrowserInterfaceBrokerRegistry>::Leaky
-    g_web_ui_browser_interface_broker_registry = LAZY_INSTANCE_INITIALIZER;
+WebUIBrowserInterfaceBrokerRegistry& GetWebUIBrowserInterfaceBrokerRegistry() {
+  static base::NoDestructor<WebUIBrowserInterfaceBrokerRegistry> registry;
+  return *registry;
+}
 }  // namespace
 
 WebUIController::WebUIController(WebUI* web_ui) : web_ui_(web_ui) {}
@@ -45,8 +48,7 @@
 void WebUIController::WebUIReadyToCommitNavigation(
     RenderFrameHost* render_frame_host) {
   broker_ =
-      g_web_ui_browser_interface_broker_registry.Get().CreateInterfaceBroker(
-          *this);
+      GetWebUIBrowserInterfaceBrokerRegistry().CreateInterfaceBroker(*this);
 
   if (broker_) {
     RenderFrameHostImpl* rfh =
diff --git a/content/public/common/profiling.cc b/content/public/common/profiling.cc
index 4e70484d..4a587b1 100644
--- a/content/public/common/profiling.cc
+++ b/content/public/common/profiling.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "base/debug/profiler.h"
 #include "base/functional/bind.h"
-#include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
@@ -102,8 +101,10 @@
   base::Lock lock_;
 };
 
-base::LazyInstance<ProfilingThreadControl>::Leaky g_flush_thread_control =
-    LAZY_INSTANCE_INITIALIZER;
+ProfilingThreadControl& GetProfilingThreadControl() {
+  static base::NoDestructor<ProfilingThreadControl> flush_thread_control;
+  return *flush_thread_control;
+}
 
 }  // namespace
 
@@ -132,12 +133,12 @@
   // Schedule profile data flushing for single process because it doesn't
   // get written out correctly on exit.
   if (flush)
-    g_flush_thread_control.Get().Start();
+    GetProfilingThreadControl().Start();
 }
 
 // static
 void Profiling::Stop() {
-  g_flush_thread_control.Get().Stop();
+  GetProfilingThreadControl().Stop();
   base::debug::StopProfiling();
 }
 
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
index 8364a97..c26cff0 100644
--- a/content/public/renderer/render_frame_observer.h
+++ b/content/public/renderer/render_frame_observer.h
@@ -21,7 +21,6 @@
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/network/public/mojom/url_response_head.mojom-forward.h"
 #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/common/subresource_load_metrics.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
@@ -30,6 +29,7 @@
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
 #include "third_party/blink/public/web/web_meaningful_layout.h"
 #include "third_party/blink/public/web/web_navigation_type.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "ui/accessibility/ax_mode.h"
 #include "ui/base/page_transition_types.h"
 #include "v8/include/v8-forward.h"
@@ -254,7 +254,8 @@
   // - Initiated with the window.history or window.navigation APIs.
   // - Accompanied with a DOM modification of the <main> element during the same
   // or a descendant task.
-  virtual void DidObserveSoftNavigation(blink::SoftNavigationMetrics metrics) {}
+  virtual void DidObserveSoftNavigation(
+      blink::SoftNavigationMetricsForReporting metrics) {}
 
   // Reports that visible elements in the frame shifted (bit.ly/lsm-explainer).
   // This is called once for each animation frame containing any layout shift,
diff --git a/content/public/test/mock_media_session.h b/content/public/test/mock_media_session.h
index 9e3b304..6801d90 100644
--- a/content/public/test/mock_media_session.h
+++ b/content/public/test/mock_media_session.h
@@ -29,6 +29,18 @@
               (const base::UnguessableToken& group_id),
               (override));
   MOCK_METHOD(content::RenderFrameHost*, GetRoutedFrame, (), (override));
+  MOCK_METHOD(media_session::mojom::MediaSessionInfoPtr,
+              GetMediaSessionInfoSync,
+              (),
+              (override));
+  MOCK_METHOD(std::optional<media_session::MediaPosition>,
+              GetMediaSessionPosition,
+              (),
+              (override));
+  MOCK_METHOD(const media_session::MediaMetadata&,
+              GetMediaSessionMetadata,
+              (),
+              (override));
   MOCK_METHOD(void, Suspend, (SuspendType suspend_type), (override));
   MOCK_METHOD(void, Resume, (SuspendType suspend_type), (override));
   MOCK_METHOD(void, StartDucking, (), (override));
diff --git a/content/public/test/test_download_http_response.cc b/content/public/test/test_download_http_response.cc
index a6bf8ae..2d86770 100644
--- a/content/public/test/test_download_http_response.cc
+++ b/content/public/test/test_download_http_response.cc
@@ -13,8 +13,8 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -31,14 +31,19 @@
 
 namespace {
 
-// Lock object for protecting |g_parameters_map|.
-base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+// Lock object for protecting |GetParametersMap()|.
+base::Lock& GetParametersMapLock() {
+  static base::NoDestructor<base::Lock> lock;
+  return *lock;
+}
 
 using ParametersMap = std::map<GURL, TestDownloadHttpResponse::Parameters>;
 // Maps url to Parameters so that requests for the same URL will get the same
 // parameters.
-base::LazyInstance<ParametersMap>::Leaky g_parameters_map =
-    LAZY_INSTANCE_INITIALIZER;
+ParametersMap& GetParametersMap() {
+  static base::NoDestructor<ParametersMap> parameters_map;
+  return *parameters_map;
+}
 
 const char* kTestDownloadPath = "/download/";
 
@@ -175,8 +180,8 @@
 void TestDownloadHttpResponse::StartServing(
     const TestDownloadHttpResponse::Parameters& parameters,
     const GURL& url) {
-  base::AutoLock lock(*g_lock.Pointer());
-  auto& parameters_map = g_parameters_map.Get();
+  base::AutoLock lock(GetParametersMapLock());
+  auto& parameters_map = GetParametersMap();
   parameters_map.erase(url);
   parameters_map.emplace(url, parameters);
 }
@@ -396,12 +401,13 @@
       // next response will be different.
       if (it->is_transient) {
         parameters_.range_request_responses.erase(it);
-        base::AutoLock lock(*g_lock.Pointer());
+        base::AutoLock lock(GetParametersMapLock());
         GURL url = GetURLFromRequest(request_);
-        auto iter = g_parameters_map.Get().find(url);
-        if (iter != g_parameters_map.Get().end())
-          g_parameters_map.Get().erase(iter);
-        g_parameters_map.Get().emplace(url, std::move(parameters_));
+        auto iter = GetParametersMap().find(url);
+        if (iter != GetParametersMap().end()) {
+          GetParametersMap().erase(iter);
+        }
+        GetParametersMap().emplace(url, std::move(parameters_));
       }
 
       return true;
@@ -638,10 +644,10 @@
     return nullptr;
   }
 
-  base::AutoLock lock(*g_lock.Pointer());
+  base::AutoLock lock(GetParametersMapLock());
   GURL url = GetURLFromRequest(request);
-  auto iter = g_parameters_map.Get().find(url);
-  if (iter != g_parameters_map.Get().end()) {
+  auto iter = GetParametersMap().find(url);
+  if (iter != GetParametersMap().end()) {
     auto test_response = std::make_unique<TestDownloadHttpResponse>(
         request, std::move(iter->second), std::move(callback));
     auto response = test_response->CreateResponseForTestServer();
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 62390212..f80c9d4 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4630,7 +4630,7 @@
 }
 
 void RenderFrameImpl::DidObserveSoftNavigation(
-    blink::SoftNavigationMetrics metrics) {
+    blink::SoftNavigationMetricsForReporting metrics) {
   for (auto& observer : observers_) {
     observer.DidObserveSoftNavigation(metrics);
   }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 5f54302..47da750 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -599,7 +599,8 @@
       const blink::SubresourceLoadMetrics& subresource_load_metrics) override;
   void DidObserveNewFeatureUsage(
       const blink::UseCounterFeature& feature) override;
-  void DidObserveSoftNavigation(blink::SoftNavigationMetrics metrics) override;
+  void DidObserveSoftNavigation(
+      blink::SoftNavigationMetricsForReporting metrics) override;
   void DidObserveLayoutShift(double score, bool after_input_or_scroll) override;
   void DidCreateScriptContext(v8::Local<v8::Context> context,
                               int world_id) override;
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index 6f6e56d..576e2f1 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -15,8 +15,8 @@
 #include "base/cpu.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/process/current_process.h"
 #include "base/strings/string_number_conversions.h"
@@ -102,8 +102,11 @@
 };
 
 #if !BUILDFLAG(IS_FUCHSIA)
-base::LazyInstance<content::ShellCrashReporterClient>::Leaky
-    g_shell_crash_client = LAZY_INSTANCE_INITIALIZER;
+content::ShellCrashReporterClient& GetShellCrashReporterClient() {
+  static base::NoDestructor<content::ShellCrashReporterClient>
+      shell_crash_client;
+  return *shell_crash_client;
+}
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -282,7 +285,7 @@
     std::string process_type =
         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
             switches::kProcessType);
-    crash_reporter::SetCrashReporterClient(g_shell_crash_client.Pointer());
+    crash_reporter::SetCrashReporterClient(&GetShellCrashReporterClient());
     // Reporting for sub-processes will be initialized in ZygoteForked.
     if (process_type != switches::kZygoteProcess) {
       crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 2588b79f..193c5b5 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -605,7 +605,6 @@
     "//device/base/synchronization",
     "//google_apis",
     "//gpu/ipc:gl_in_process_context",
-    "//ipc:test_sink",
     "//media",
     "//media/capture",
     "//media/capture/mojom:image_capture",
@@ -1921,7 +1920,6 @@
     "//gin",
     "//gpu/ipc/host",
     "//ipc",
-    "//ipc:test_sink",
     "//media:media_buildflags",
     "//media:test_support",
     "//media/midi:midi",
@@ -3225,7 +3223,6 @@
     "//gpu/ipc/common:test_support",
     "//gpu/ipc/host",
     "//gpu/ipc/service",
-    "//ipc:test_sink",
     "//media:test_support",
     "//media/capture",
     "//media/midi:midi",
diff --git a/content/test/data/indexeddb/bug_90635.js b/content/test/data/indexeddb/bug_90635.js
index a54f94c..948b57bd 100644
--- a/content/test/data/indexeddb/bug_90635.js
+++ b/content/test/data/indexeddb/bug_90635.js
@@ -29,6 +29,7 @@
       db.createObjectStore('store1');
       db.createObjectStore('store2', {keyPath: ''});
       db.createObjectStore('store3', {keyPath: 'some_path'});
+      db.createObjectStore('store4', {keyPath: ['', '']});
     };
     openreq.onsuccess = function() {
       test_store(db, 'first run');
@@ -40,6 +41,8 @@
 {
   var openreq = window.indexedDB.open('bug90635');
   openreq.onerror = unexpectedErrorCallback;
+  openreq.onblocked = unexpectedBlockedCallback;
+  openreq.onupgradeneeded = unexpectedUpgradeNeededCallback;
   openreq.onsuccess = function(e) {
     var db = openreq.result;
     test_store(db, 'second run');
@@ -47,14 +50,16 @@
 }
 
 function test_store(db, msg) {
-  var transaction = db.transaction(['store1', 'store2', 'store3'], 'readonly');
+  var transaction =
+      db.transaction(['store1', 'store2', 'store3', 'store4'], 'readonly');
   var store1 = transaction.objectStore('store1');
   var store2 = transaction.objectStore('store2');
   var store3 = transaction.objectStore('store3');
+  var store4 = transaction.objectStore('store4');
 
-  if (store1.keyPath !== null ||
-      store2.keyPath !== '' ||
-      store3.keyPath !== 'some_path') {
+  if (store1.keyPath !== null || store2.keyPath !== '' ||
+      store3.keyPath !== 'some_path' || store4.keyPath.length !== 2 ||
+      store4.keyPath[0] !== '' || store4.keyPath[1] !== '') {
     result('fail - ' + msg);
   } else {
     result('pass - ' + msg);
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index f291a05f..54216c4 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -519,6 +519,7 @@
       ui::PAGE_TRANSITION_LINK,
       /*should_warm_up_compositor=*/false,
       /*should_prepare_paint_tree=*/false,
+      /*should_pause_javascript_execution=*/false,
       /*url_match_predicate=*/{},
       /*prerender_navigation_handle_callback=*/{},
       PreloadPipelineInfoImpl::Create(
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn
index cb5da86..b1d9395 100644
--- a/content/utility/BUILD.gn
+++ b/content/utility/BUILD.gn
@@ -128,7 +128,7 @@
     }
   }
 
-  if ((is_chromeos || is_linux) && is_chrome_branded) {
+  if (is_chromeos && is_chrome_branded) {
     deps += [
       "//services/shape_detection:lib",
       "//services/shape_detection/public/mojom",
diff --git a/content/utility/services.cc b/content/utility/services.cc
index 6d79367e..307adb1d 100644
--- a/content/utility/services.cc
+++ b/content/utility/services.cc
@@ -8,7 +8,7 @@
 
 #include "base/command_line.h"
 #include "base/feature_list.h"
-#include "base/lazy_instance.h"
+#include "base/no_destructor.h"
 #include "base/task/single_thread_task_runner.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
@@ -80,7 +80,7 @@
 #include "sandbox/policy/sandbox_type.h"
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
 #include "services/shape_detection/public/mojom/shape_detection_service.mojom.h"  // nogncheck
 #include "services/shape_detection/shape_detection_service.h"  // nogncheck
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
@@ -122,8 +122,10 @@
 #endif  // BUILDFLAG(ENABLE_GPU_CHANNEL_MEDIA_CAPTURE)
 
 namespace content {
-base::LazyInstance<NetworkBinderCreationCallback>::Leaky
-    g_network_binder_creation_callback_for_testing = LAZY_INSTANCE_INITIALIZER;
+NetworkBinderCreationCallback& GetNetworkBinderCreationCallbackForTesting() {
+  static base::NoDestructor<NetworkBinderCreationCallback> callback;
+  return *callback;
+}
 
 namespace {
 
@@ -188,9 +190,8 @@
 auto RunNetworkService(
     mojo::PendingReceiver<network::mojom::NetworkService> receiver) {
   auto binders = std::make_unique<service_manager::BinderRegistry>();
-  if (g_network_binder_creation_callback_for_testing.Get()) {
-    std::move(g_network_binder_creation_callback_for_testing.Get())
-        .Run(binders.get());
+  if (GetNetworkBinderCreationCallbackForTesting()) {
+    std::move(GetNetworkBinderCreationCallbackForTesting()).Run(binders.get());
   }
   return std::make_unique<network::NetworkService>(
       std::move(binders), std::move(receiver),
@@ -256,7 +257,7 @@
   return audio::CreateStandaloneService(std::move(receiver));
 }
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
 auto RunShapeDetectionService(
     mojo::PendingReceiver<shape_detection::mojom::ShapeDetectionService>
         receiver) {
@@ -398,7 +399,7 @@
 
 void SetNetworkBinderCreationCallbackForTesting(  // IN-TEST
     NetworkBinderCreationCallback callback) {
-  g_network_binder_creation_callback_for_testing.Get() = std::move(callback);
+  GetNetworkBinderCreationCallbackForTesting() = std::move(callback);
 }
 
 void RegisterIOThreadServices(mojo::ServiceFactory& services) {
@@ -431,7 +432,7 @@
     services.Add(RunOnDeviceModel);
   }
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX))
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
   services.Add(RunShapeDetectionService);
 #endif
 
diff --git a/content/utility/utility_main.cc b/content/utility/utility_main.cc
index 6afc5ab..9cc954c9 100644
--- a/content/utility/utility_main.cc
+++ b/content/utility/utility_main.cc
@@ -53,7 +53,6 @@
 #include "services/audio/audio_sandbox_hook_linux.h"
 #include "services/network/network_sandbox_hook_linux.h"
 #include "services/screen_ai/buildflags/buildflags.h"
-#include "services/shape_detection/shape_detection_sandbox_hook.h"
 
 #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION)
 #include "gpu/config/gpu_info_collector.h"
@@ -96,6 +95,8 @@
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
 #include "chromeos/ash/services/libassistant/libassistant_sandbox_hook.h"  // nogncheck
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
+
+#include "services/shape_detection/shape_detection_sandbox_hook.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_MAC)
@@ -356,10 +357,6 @@
       break;
 #endif  // BUILDFLAG(IS_LINUX)
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-    case sandbox::mojom::Sandbox::kShapeDetection:
-      pre_sandbox_hook =
-          base::BindOnce(&shape_detection::ShapeDetectionPreSandboxHook);
-      break;
 #if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
     case sandbox::mojom::Sandbox::kHardwareVideoDecoding:
       pre_sandbox_hook =
@@ -380,6 +377,10 @@
     case sandbox::mojom::Sandbox::kTts:
       pre_sandbox_hook = base::BindOnce(&chromeos::tts::TtsPreSandboxHook);
       break;
+    case sandbox::mojom::Sandbox::kShapeDetection:
+      pre_sandbox_hook =
+          base::BindOnce(&shape_detection::ShapeDetectionPreSandboxHook);
+      break;
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
     case sandbox::mojom::Sandbox::kLibassistant:
       pre_sandbox_hook =
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn
index e96ff9e..11aed54 100644
--- a/crypto/BUILD.gn
+++ b/crypto/BUILD.gn
@@ -83,20 +83,20 @@
 
   if (is_apple) {
     sources += [
-      "apple_keychain.cc",
-      "apple_keychain.h",
-      "apple_keychain_secitem.h",
-      "apple_keychain_secitem.mm",
-      "apple_keychain_util.h",
-      "apple_keychain_util.mm",
-      "apple_keychain_v2.h",
-      "apple_keychain_v2.mm",
+      "apple/keychain.cc",
+      "apple/keychain.h",
+      "apple/keychain_secitem.h",
+      "apple/keychain_secitem.mm",
+      "apple/keychain_util.h",
+      "apple/keychain_util.mm",
+      "apple/keychain_v2.h",
+      "apple/keychain_v2.mm",
     ]
 
     if (is_mac) {
       sources += [
-        "apple_keychain_seckeychain.cc",
-        "apple_keychain_seckeychain.h",
+        "apple/keychain_seckeychain.cc",
+        "apple/keychain_seckeychain.h",
         "mac_security_services_lock.cc",
         "mac_security_services_lock.h",
         "scoped_lacontext.h",
@@ -158,10 +158,11 @@
 }
 
 if (is_apple) {
+  # TODO(https://crbug.com/431952820): move this into a crypto/apple/BUILD.gn
   source_set("mock_apple_keychain") {
     sources = [
-      "mock_apple_keychain.cc",
-      "mock_apple_keychain.h",
+      "apple/mock_keychain.cc",
+      "apple/mock_keychain.h",
     ]
 
     deps = [
@@ -198,16 +199,16 @@
   }
 
   if (is_apple) {
-    sources += [ "mock_apple_keychain_unittest.cc" ]
+    sources += [ "apple/mock_keychain_unittest.cc" ]
   }
 
   if (is_ios) {
-    sources += [ "apple_keychain_secitem_ios_unittest.mm" ]
+    sources += [ "apple/keychain_secitem_ios_unittest.mm" ]
   }
 
   if (is_mac) {
     sources += [
-      "apple_keychain_util_unittest.mm",
+      "apple/keychain_util_unittest.mm",
       "unexportable_key_mac_unittest.mm",
       "user_verifying_key_mac_unittest.mm",
     ]
@@ -275,10 +276,10 @@
 
   if (is_mac) {
     sources += [
-      "fake_apple_keychain_v2.h",
-      "fake_apple_keychain_v2.mm",
-      "scoped_fake_apple_keychain_v2.h",
-      "scoped_fake_apple_keychain_v2.mm",
+      "apple/fake_keychain_v2.h",
+      "apple/fake_keychain_v2.mm",
+      "apple/scoped_fake_keychain_v2.h",
+      "apple/scoped_fake_keychain_v2.mm",
     ]
     frameworks = [
       "CoreFoundation.framework",
diff --git a/crypto/fake_apple_keychain_v2.h b/crypto/apple/fake_keychain_v2.h
similarity index 69%
rename from crypto/fake_apple_keychain_v2.h
rename to crypto/apple/fake_keychain_v2.h
index f307965..c3d43823 100644
--- a/crypto/fake_apple_keychain_v2.h
+++ b/crypto/apple/fake_keychain_v2.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 CRYPTO_FAKE_APPLE_KEYCHAIN_V2_H_
-#define CRYPTO_FAKE_APPLE_KEYCHAIN_V2_H_
+#ifndef CRYPTO_APPLE_FAKE_KEYCHAIN_V2_H_
+#define CRYPTO_APPLE_FAKE_KEYCHAIN_V2_H_
 
 #import <Foundation/Foundation.h>
 
@@ -11,24 +11,24 @@
 #include <vector>
 
 #include "base/apple/scoped_cftyperef.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "crypto/crypto_export.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
 
-namespace crypto {
+namespace crypto::apple {
 
-// FakeAppleKeychainV2 is an implementation of AppleKeychainV2 for testing. It
-// works around behavior that can't be relied on in tests, such as writing to
-// the actual Keychain or using functionality that requires code-signed,
-// entitled builds.
-class CRYPTO_EXPORT FakeAppleKeychainV2 : public AppleKeychainV2 {
+// FakeKeychainV2 is an implementation of KeychainV2 for testing. It works
+// around behavior that can't be relied on in tests, such as writing to the
+// actual Keychain or using functionality that requires code-signed, entitled
+// builds.
+class CRYPTO_EXPORT FakeKeychainV2 : public KeychainV2 {
  public:
-  using UVMethod = ScopedFakeAppleKeychainV2::UVMethod;
+  using UVMethod = ScopedFakeKeychainV2::UVMethod;
 
-  explicit FakeAppleKeychainV2(const std::string& keychain_access_group);
-  FakeAppleKeychainV2(const FakeAppleKeychainV2&) = delete;
-  FakeAppleKeychainV2& operator=(const FakeAppleKeychainV2&) = delete;
-  ~FakeAppleKeychainV2() override;
+  explicit FakeKeychainV2(const std::string& keychain_access_group);
+  FakeKeychainV2(const FakeKeychainV2&) = delete;
+  FakeKeychainV2& operator=(const FakeKeychainV2&) = delete;
+  ~FakeKeychainV2() override;
 
   const std::vector<base::apple::ScopedCFTypeRef<CFDictionaryRef>>& items() {
     return items_;
@@ -40,7 +40,7 @@
 
   void set_uv_method(UVMethod uv_method) { uv_method_ = uv_method; }
 
-  // AppleKeychainV2:
+  // KeychainV2:
   NSArray* GetTokenIDs() override;
   base::apple::ScopedCFTypeRef<SecKeyRef> KeyCreateRandomKey(
       CFDictionaryRef params,
@@ -75,6 +75,6 @@
   base::apple::ScopedCFTypeRef<CFStringRef> keychain_access_group_;
 };
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
-#endif  // CRYPTO_FAKE_APPLE_KEYCHAIN_V2_H_
+#endif  // CRYPTO_APPLE_FAKE_KEYCHAIN_V2_H_
diff --git a/crypto/fake_apple_keychain_v2.mm b/crypto/apple/fake_keychain_v2.mm
similarity index 91%
rename from crypto/fake_apple_keychain_v2.mm
rename to crypto/apple/fake_keychain_v2.mm
index 72601fd..2edf8012 100644
--- a/crypto/fake_apple_keychain_v2.mm
+++ b/crypto/apple/fake_keychain_v2.mm
@@ -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 "crypto/fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
 
 #import <CoreFoundation/CoreFoundation.h>
 #import <Foundation/Foundation.h>
@@ -20,19 +20,18 @@
 #include "base/memory/scoped_policy.h"
 #include "base/notimplemented.h"
 #include "base/strings/sys_string_conversions.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 
 #if defined(LEAK_SANITIZER)
 #include <sanitizer/lsan_interface.h>
 #endif
 
-namespace crypto {
+namespace crypto::apple {
 
-FakeAppleKeychainV2::FakeAppleKeychainV2(
-    const std::string& keychain_access_group)
+FakeKeychainV2::FakeKeychainV2(const std::string& keychain_access_group)
     : keychain_access_group_(
           base::SysUTF8ToCFStringRef(keychain_access_group)) {}
-FakeAppleKeychainV2::~FakeAppleKeychainV2() {
+FakeKeychainV2::~FakeKeychainV2() {
   // Avoid shutdown leak of error string in Security.framework.
   // See
   // https://github.com/apple-oss-distributions/Security/blob/Security-60158.140.3/OSX/libsecurity_keychain/lib/SecBase.cpp#L88
@@ -41,14 +40,14 @@
 #endif
 }
 
-NSArray* FakeAppleKeychainV2::GetTokenIDs() {
+NSArray* FakeKeychainV2::GetTokenIDs() {
   if (is_secure_enclave_available_) {
     return @[ base::apple::CFToNSPtrCast(kSecAttrTokenIDSecureEnclave) ];
   }
   return @[];
 }
 
-base::apple::ScopedCFTypeRef<SecKeyRef> FakeAppleKeychainV2::KeyCreateRandomKey(
+base::apple::ScopedCFTypeRef<SecKeyRef> FakeKeychainV2::KeyCreateRandomKey(
     CFDictionaryRef params,
     CFErrorRef* error) {
   // Validate certain fields that we always expect to be set.
@@ -129,8 +128,8 @@
   return private_key;
 }
 
-base::apple::ScopedCFTypeRef<CFDictionaryRef>
-FakeAppleKeychainV2::KeyCopyAttributes(SecKeyRef key) {
+base::apple::ScopedCFTypeRef<CFDictionaryRef> FakeKeychainV2::KeyCopyAttributes(
+    SecKeyRef key) {
   const auto& it = std::ranges::find_if(items_, [&key](const auto& item) {
     return CFEqual(key, CFDictionaryGetValue(item.get(), kSecValueRef));
   });
@@ -145,8 +144,8 @@
   return result;
 }
 
-OSStatus FakeAppleKeychainV2::ItemAdd(CFDictionaryRef attributes,
-                                      CFTypeRef* result) {
+OSStatus FakeKeychainV2::ItemAdd(CFDictionaryRef attributes,
+                                 CFTypeRef* result) {
   CFStringRef keychain_access_group =
       base::apple::GetValueFromDictionary<CFStringRef>(attributes,
                                                        kSecAttrAccessGroup);
@@ -159,8 +158,8 @@
   return errSecSuccess;
 }
 
-OSStatus FakeAppleKeychainV2::ItemCopyMatching(CFDictionaryRef query,
-                                               CFTypeRef* result) {
+OSStatus FakeKeychainV2::ItemCopyMatching(CFDictionaryRef query,
+                                          CFTypeRef* result) {
   // In practice we don't need to care about limit queries, or leaving out the
   // SecKeyRef or attributes from the result set.
   DCHECK_EQ(
@@ -239,7 +238,7 @@
   return errSecSuccess;
 }
 
-OSStatus FakeAppleKeychainV2::ItemDelete(CFDictionaryRef query) {
+OSStatus FakeKeychainV2::ItemDelete(CFDictionaryRef query) {
   // Validate certain fields that we always expect to be set.
   DCHECK_EQ(base::apple::GetValueFromDictionary<CFStringRef>(query, kSecClass),
             kSecClassKey);
@@ -266,8 +265,8 @@
   return errSecItemNotFound;
 }
 
-OSStatus FakeAppleKeychainV2::ItemUpdate(CFDictionaryRef query,
-                                         CFDictionaryRef attributes_to_update) {
+OSStatus FakeKeychainV2::ItemUpdate(CFDictionaryRef query,
+                                    CFDictionaryRef attributes_to_update) {
   DCHECK_EQ(base::apple::GetValueFromDictionary<CFStringRef>(query, kSecClass),
             kSecClassKey);
   DCHECK(CFEqual(base::apple::GetValueFromDictionary<CFStringRef>(
@@ -299,9 +298,9 @@
 
 #if !BUILDFLAG(IS_IOS)
 base::apple::ScopedCFTypeRef<CFTypeRef>
-FakeAppleKeychainV2::TaskCopyValueForEntitlement(SecTaskRef task,
-                                                 CFStringRef entitlement,
-                                                 CFErrorRef* error) {
+FakeKeychainV2::TaskCopyValueForEntitlement(SecTaskRef task,
+                                            CFStringRef entitlement,
+                                            CFErrorRef* error) {
   CHECK(task);
   CHECK(CFEqual(entitlement,
                 base::SysUTF8ToCFStringRef("keychain-access-groups").get()))
@@ -317,7 +316,7 @@
 #endif  // !BUILDFLAG(IS_IOS)
 
 #if !BUILDFLAG(IS_IOS_TVOS)
-BOOL FakeAppleKeychainV2::LAContextCanEvaluatePolicy(
+BOOL FakeKeychainV2::LAContextCanEvaluatePolicy(
     LAPolicy policy,
     NSError* __autoreleasing* error) {
   switch (policy) {
@@ -336,4 +335,4 @@
 }
 #endif  // !BUILDFLAG(IS_IOS_TVOS)
 
-}  // namespace crypto
+}  // namespace crypto::apple
diff --git a/crypto/apple_keychain.cc b/crypto/apple/keychain.cc
similarity index 80%
rename from crypto/apple_keychain.cc
rename to crypto/apple/keychain.cc
index e0662f78..8dbc87e 100644
--- a/crypto/apple_keychain.cc
+++ b/crypto/apple/keychain.cc
@@ -2,20 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 
 #include <memory>
 
 #include "base/feature_list.h"
 #include "build/build_config.h"
-#include "crypto/apple_keychain_secitem.h"
+#include "crypto/apple/keychain_secitem.h"
 #include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
 
 #if BUILDFLAG(IS_MAC)
-#include "crypto/apple_keychain_seckeychain.h"
+#include "crypto/apple/keychain_seckeychain.h"
 #endif
 
-namespace crypto {
+namespace crypto::apple {
 
 #if BUILDFLAG(IS_MAC)
 BASE_FEATURE(kAppleKeychainUseSecItem,
@@ -24,20 +24,20 @@
 #endif
 
 // static
-std::unique_ptr<AppleKeychain> AppleKeychain::DefaultKeychain() {
+std::unique_ptr<Keychain> Keychain::DefaultKeychain() {
 #if BUILDFLAG(IS_MAC)
   if (base::FeatureList::IsEnabled(kAppleKeychainUseSecItem)) {
-    return std::make_unique<AppleKeychainSecItem>();
+    return std::make_unique<KeychainSecItem>();
   }
 
-  return std::make_unique<AppleKeychainSecKeychain>();
+  return std::make_unique<KeychainSecKeychain>();
 #else
-  return std::make_unique<AppleKeychainSecItem>();
+  return std::make_unique<KeychainSecItem>();
 #endif
 }
 
-AppleKeychain::AppleKeychain() = default;
-AppleKeychain::~AppleKeychain() = default;
+Keychain::Keychain() = default;
+Keychain::~Keychain() = default;
 
 #if BUILDFLAG(IS_MAC)
 
@@ -89,4 +89,4 @@
 
 #endif  // BUILDFLAG(IS_MAC)
 
-}  // namespace crypto
+}  // namespace crypto::apple
diff --git a/crypto/apple_keychain.h b/crypto/apple/keychain.h
similarity index 87%
rename from crypto/apple_keychain.h
rename to crypto/apple/keychain.h
index 605a6db..2438c39 100644
--- a/crypto/apple_keychain.h
+++ b/crypto/apple/keychain.h
@@ -16,9 +16,9 @@
 #include "build/build_config.h"
 #include "crypto/crypto_export.h"
 
-namespace crypto {
+namespace crypto::apple {
 
-// DEPRECATED: use `AppleKeychainV2` instead.
+// DEPRECATED: use `KeychainV2` instead.
 // Wraps the KeychainServices API in a very thin layer, to allow it to be
 // mocked out for testing.
 
@@ -26,20 +26,20 @@
 // through directly to their Keychain Services equivalents (Foo ->
 // SecKeychainFoo).
 //
-// New code should use AppleKeychainV2.
-class CRYPTO_EXPORT AppleKeychain {
+// New code should use KeychainV2.
+class CRYPTO_EXPORT Keychain {
  public:
   // Returns an object suitable for accessing the platform's default type of
   // keychain.
   //
   // On macOS, this will access the default file-based keychain. On
   // iOS, this will access the application's data protection keychain.
-  static std::unique_ptr<AppleKeychain> DefaultKeychain();
+  static std::unique_ptr<Keychain> DefaultKeychain();
 
-  AppleKeychain(const AppleKeychain&) = delete;
-  AppleKeychain& operator=(const AppleKeychain&) = delete;
+  Keychain(const Keychain&) = delete;
+  Keychain& operator=(const Keychain&) = delete;
 
-  virtual ~AppleKeychain();
+  virtual ~Keychain();
 
   // Note that even though OSStatus has a noError value, that can never be
   // returned in the OSStatus arm of FindGenericPassword() - in that case, the
@@ -54,7 +54,7 @@
       base::span<const uint8_t> password) const = 0;
 
  protected:
-  AppleKeychain();
+  Keychain();
 };
 
 #if BUILDFLAG(IS_MAC)
@@ -85,6 +85,6 @@
 
 #endif  // BUILDFLAG(IS_MAC)
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
 #endif  // CRYPTO_APPLE_KEYCHAIN_H_
diff --git a/crypto/apple_keychain_secitem.h b/crypto/apple/keychain_secitem.h
similarity index 69%
rename from crypto/apple_keychain_secitem.h
rename to crypto/apple/keychain_secitem.h
index 1632c22..eb74282 100644
--- a/crypto/apple_keychain_secitem.h
+++ b/crypto/apple/keychain_secitem.h
@@ -5,15 +5,15 @@
 #ifndef CRYPTO_APPLE_KEYCHAIN_SECITEM_H_
 #define CRYPTO_APPLE_KEYCHAIN_SECITEM_H_
 
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 
-namespace crypto {
+namespace crypto::apple {
 
-// An implementation of AppleKeychain on top of the SecItem API.
-class CRYPTO_EXPORT AppleKeychainSecItem : public AppleKeychain {
+// An implementation of Keychain on top of the SecItem API.
+class CRYPTO_EXPORT KeychainSecItem : public Keychain {
  public:
-  AppleKeychainSecItem();
-  ~AppleKeychainSecItem() override;
+  KeychainSecItem();
+  ~KeychainSecItem() override;
 
   base::expected<std::vector<uint8_t>, OSStatus> FindGenericPassword(
       std::string_view service_name,
@@ -25,6 +25,6 @@
       base::span<const uint8_t> password) const override;
 };
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
 #endif  // CRYPTO_APPLE_KEYCHAIN_SECITEM_H_
diff --git a/crypto/apple_keychain_secitem.mm b/crypto/apple/keychain_secitem.mm
similarity index 94%
rename from crypto/apple_keychain_secitem.mm
rename to crypto/apple/keychain_secitem.mm
index 14d7265..d2b9526f9 100644
--- a/crypto/apple_keychain_secitem.mm
+++ b/crypto/apple/keychain_secitem.mm
@@ -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 "crypto/apple_keychain_secitem.h"
+#include "crypto/apple/keychain_secitem.h"
 
 #import <Foundation/Foundation.h>
 
@@ -128,13 +128,13 @@
 
 }  // namespace
 
-namespace crypto {
+namespace crypto::apple {
 
-AppleKeychainSecItem::AppleKeychainSecItem() = default;
+KeychainSecItem::KeychainSecItem() = default;
 
-AppleKeychainSecItem::~AppleKeychainSecItem() = default;
+KeychainSecItem::~KeychainSecItem() = default;
 
-OSStatus AppleKeychainSecItem::AddGenericPassword(
+OSStatus KeychainSecItem::AddGenericPassword(
     std::string_view service_name,
     std::string_view account_name,
     base::span<const uint8_t> password) const {
@@ -160,8 +160,8 @@
 }
 
 base::expected<std::vector<uint8_t>, OSStatus>
-AppleKeychainSecItem::FindGenericPassword(std::string_view service_name,
-                                          std::string_view account_name) const {
+KeychainSecItem::FindGenericPassword(std::string_view service_name,
+                                     std::string_view account_name) const {
   base::apple::ScopedCFTypeRef<CFDictionaryRef> query =
       MakeGenericPasswordQuery(service_name, account_name);
 
@@ -203,4 +203,4 @@
   return base::ToVector(base::apple::CFDataToSpan(password_data));
 }
 
-}  // namespace crypto
+}  // namespace crypto::apple
diff --git a/crypto/apple_keychain_secitem_ios_unittest.mm b/crypto/apple/keychain_secitem_ios_unittest.mm
similarity index 98%
rename from crypto/apple_keychain_secitem_ios_unittest.mm
rename to crypto/apple/keychain_secitem_ios_unittest.mm
index 1307444..d1901a6 100644
--- a/crypto/apple_keychain_secitem_ios_unittest.mm
+++ b/crypto/apple/keychain_secitem_ios_unittest.mm
@@ -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 "crypto/apple_keychain_secitem.h"
+#import "crypto/apple/keychain_secitem.h"
 
 #import <Foundation/Foundation.h>
 
@@ -85,7 +85,7 @@
     SecItemDelete(base::apple::NSToCFPtrCast(query));
   }
 
-  crypto::AppleKeychainSecItem keychain_;
+  crypto::apple::KeychainSecItem keychain_;
   base::test::ScopedFeatureList feature_list_;
 };
 
diff --git a/crypto/apple_keychain_seckeychain.cc b/crypto/apple/keychain_seckeychain.cc
similarity index 82%
rename from crypto/apple_keychain_seckeychain.cc
rename to crypto/apple/keychain_seckeychain.cc
index c7f015a..4ad5acb 100644
--- a/crypto/apple_keychain_seckeychain.cc
+++ b/crypto/apple/keychain_seckeychain.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 "crypto/apple_keychain_seckeychain.h"
+#include "crypto/apple/keychain_seckeychain.h"
 
 #include "base/containers/span.h"
 #include "base/containers/to_vector.h"
@@ -17,16 +17,15 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 
-namespace crypto {
+namespace crypto::apple {
 
-AppleKeychainSecKeychain::AppleKeychainSecKeychain() = default;
+KeychainSecKeychain::KeychainSecKeychain() = default;
 
-AppleKeychainSecKeychain::~AppleKeychainSecKeychain() = default;
+KeychainSecKeychain::~KeychainSecKeychain() = default;
 
 base::expected<std::vector<uint8_t>, OSStatus>
-AppleKeychainSecKeychain::FindGenericPassword(
-    std::string_view service_name,
-    std::string_view account_name) const {
+KeychainSecKeychain::FindGenericPassword(std::string_view service_name,
+                                         std::string_view account_name) const {
   base::AutoLock lock(GetMacSecurityServicesLock());
   uint32_t password_length = 0;
   void* password_data = nullptr;
@@ -47,7 +46,7 @@
   return result;
 }
 
-OSStatus AppleKeychainSecKeychain::AddGenericPassword(
+OSStatus KeychainSecKeychain::AddGenericPassword(
     std::string_view service_name,
     std::string_view account_name,
     base::span<const uint8_t> password) const {
@@ -61,4 +60,4 @@
 
 #pragma clang diagnostic pop
 
-}  // namespace crypto
+}  // namespace crypto::apple
diff --git a/crypto/apple_keychain_seckeychain.h b/crypto/apple/keychain_seckeychain.h
similarity index 71%
rename from crypto/apple_keychain_seckeychain.h
rename to crypto/apple/keychain_seckeychain.h
index ecf5e229..991b2c8 100644
--- a/crypto/apple_keychain_seckeychain.h
+++ b/crypto/apple/keychain_seckeychain.h
@@ -5,18 +5,18 @@
 #ifndef CRYPTO_APPLE_KEYCHAIN_SECKEYCHAIN_H_
 #define CRYPTO_APPLE_KEYCHAIN_SECKEYCHAIN_H_
 
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 
-namespace crypto {
+namespace crypto::apple {
 
-// An implementation of AppleKeychain on top of the deprecated SecKeychain API.
+// An implementation of Keychain on top of the deprecated SecKeychain API.
 //
 // The underlying API was deprecated as of the macOS 13 SDK.
 // Removal of its use is tracked in https://crbug.com/1348251
-class CRYPTO_EXPORT AppleKeychainSecKeychain : public AppleKeychain {
+class CRYPTO_EXPORT KeychainSecKeychain : public Keychain {
  public:
-  AppleKeychainSecKeychain();
-  ~AppleKeychainSecKeychain() override;
+  KeychainSecKeychain();
+  ~KeychainSecKeychain() override;
 
   base::expected<std::vector<uint8_t>, OSStatus> FindGenericPassword(
       std::string_view service_name,
@@ -28,6 +28,6 @@
       base::span<const uint8_t> password) const override;
 };
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
 #endif  // CRYPTO_APPLE_KEYCHAIN_SECKEYCHAIN_H_
diff --git a/crypto/apple_keychain_util.h b/crypto/apple/keychain_util.h
similarity index 92%
rename from crypto/apple_keychain_util.h
rename to crypto/apple/keychain_util.h
index 2ab9f75..c7bc0338 100644
--- a/crypto/apple_keychain_util.h
+++ b/crypto/apple/keychain_util.h
@@ -10,7 +10,7 @@
 #include "build/build_config.h"
 #include "crypto/crypto_export.h"
 
-namespace crypto {
+namespace crypto::apple {
 
 #if !BUILDFLAG(IS_IOS)
 // Returns whether the main executable is signed with a keychain-access-groups
@@ -20,6 +20,6 @@
     const std::string& keychain_access_group);
 #endif  // !BUILDFLAG(IS_IOS)
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
 #endif  // CRYPTO_APPLE_KEYCHAIN_UTIL_H_
diff --git a/crypto/apple_keychain_util.mm b/crypto/apple/keychain_util.mm
similarity index 84%
rename from crypto/apple_keychain_util.mm
rename to crypto/apple/keychain_util.mm
index 74bcf0b..7124c9c 100644
--- a/crypto/apple_keychain_util.mm
+++ b/crypto/apple/keychain_util.mm
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crypto/apple_keychain_util.h"
-
-#include <string>
+#include "crypto/apple/keychain_util.h"
 
 #import <Security/Security.h>
 
+#include <string>
+
 #include "base/apple/bridging.h"
 #include "base/apple/foundation_util.h"
 #include "base/apple/scoped_cftyperef.h"
 #include "base/strings/sys_string_conversions.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 
-namespace crypto {
+namespace crypto::apple {
 
 #if !BUILDFLAG(IS_IOS)
 bool ExecutableHasKeychainAccessGroupEntitlement(
@@ -25,7 +25,7 @@
   }
 
   base::apple::ScopedCFTypeRef<CFTypeRef> entitlement_value_cftype(
-      AppleKeychainV2::GetInstance().TaskCopyValueForEntitlement(
+      KeychainV2::GetInstance().TaskCopyValueForEntitlement(
           task.get(), CFSTR("keychain-access-groups"), nullptr));
   if (!entitlement_value_cftype) {
     return false;
@@ -42,4 +42,4 @@
 }
 #endif  // !BUILDFLAG(IS_IOS)
 
-}  // namespace crypto
+}  // namespace crypto::apple
diff --git a/crypto/apple_keychain_util_unittest.mm b/crypto/apple/keychain_util_unittest.mm
similarity index 63%
rename from crypto/apple_keychain_util_unittest.mm
rename to crypto/apple/keychain_util_unittest.mm
index 876c7584..193aad6 100644
--- a/crypto/apple_keychain_util_unittest.mm
+++ b/crypto/apple/keychain_util_unittest.mm
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crypto/apple_keychain_util.h"
+#include "crypto/apple/keychain_util.h"
 
-#include "crypto/fake_apple_keychain_v2.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -14,15 +14,15 @@
 
 class AppleKeychainUtilTest : public testing::Test {
  protected:
-  crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_keychain_{
       kTestKeychainAccessGroup};
 };
 
 #if !BUILDFLAG(IS_IOS)
 TEST_F(AppleKeychainUtilTest, ExecutableHasKeychainAccessGroupEntitlement) {
-  EXPECT_TRUE(crypto::ExecutableHasKeychainAccessGroupEntitlement(
+  EXPECT_TRUE(crypto::apple::ExecutableHasKeychainAccessGroupEntitlement(
       kTestKeychainAccessGroup));
-  EXPECT_FALSE(crypto::ExecutableHasKeychainAccessGroupEntitlement(
+  EXPECT_FALSE(crypto::apple::ExecutableHasKeychainAccessGroupEntitlement(
       "some-other-keychain-access-group"));
 }
 #endif  // !BUILDFLAG(IS_IOS)
diff --git a/crypto/apple_keychain_v2.h b/crypto/apple/keychain_v2.h
similarity index 85%
rename from crypto/apple_keychain_v2.h
rename to crypto/apple/keychain_v2.h
index fd679727..27d701f 100644
--- a/crypto/apple_keychain_v2.h
+++ b/crypto/apple/keychain_v2.h
@@ -9,25 +9,25 @@
 #import <Foundation/Foundation.h>
 #import <Security/Security.h>
 
-#include "crypto/crypto_export.h"
 #include "base/apple/scoped_cftyperef.h"
 #include "base/no_destructor.h"
+#include "crypto/crypto_export.h"
 
 #if !BUILDFLAG(IS_IOS_TVOS)
 #import <LocalAuthentication/LocalAuthentication.h>
 #endif
 
-namespace crypto {
+namespace crypto::apple {
 
-// AppleKeychainV2 wraps iOS-style operations from the macOS Security framework
+// KeychainV2 wraps iOS-style operations from the macOS Security framework
 // to work with keys and keychain items. These functions are grouped here so
 // they can be mocked out in testing.
-class CRYPTO_EXPORT AppleKeychainV2 {
+class CRYPTO_EXPORT KeychainV2 {
  public:
-  static AppleKeychainV2& GetInstance();
+  static KeychainV2& GetInstance();
 
-  AppleKeychainV2(const AppleKeychainV2&) = delete;
-  AppleKeychainV2& operator=(const AppleKeychainV2&) = delete;
+  KeychainV2(const KeychainV2&) = delete;
+  KeychainV2& operator=(const KeychainV2&) = delete;
 
   // Wraps the |TKTokenWatcher.tokenIDs| property.
   virtual NSArray* GetTokenIDs();
@@ -79,21 +79,21 @@
 #endif  // !BUILDFLAG(IS_IOS_TVOS)
 
  protected:
-  AppleKeychainV2();
-  virtual ~AppleKeychainV2();
+  KeychainV2();
+  virtual ~KeychainV2();
 
  protected:
-  friend class base::NoDestructor<AppleKeychainV2>;
+  friend class base::NoDestructor<KeychainV2>;
   friend class ScopedTouchIdTestEnvironment;
-  friend class ScopedFakeAppleKeychainV2;
+  friend class ScopedFakeKeychainV2;
 
   // Set an override to the singleton instance returned by |GetInstance|. The
   // caller keeps ownership of the injected keychain and must remove the
   // override by calling |ClearInstanceOverride| before deleting it.
-  static void SetInstanceOverride(AppleKeychainV2* keychain);
+  static void SetInstanceOverride(KeychainV2* keychain);
   static void ClearInstanceOverride();
 };
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
 #endif  // CRYPTO_APPLE_KEYCHAIN_V2_H_
diff --git a/crypto/apple/keychain_v2.mm b/crypto/apple/keychain_v2.mm
new file mode 100644
index 0000000..ecc4fc5b
--- /dev/null
+++ b/crypto/apple/keychain_v2.mm
@@ -0,0 +1,114 @@
+// 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 "crypto/apple/keychain_v2.h"
+
+#import <CryptoTokenKit/CryptoTokenKit.h>
+#import <Foundation/Foundation.h>
+
+#include "base/apple/foundation_util.h"
+#include "base/apple/scoped_cftyperef.h"
+#include "base/no_destructor.h"
+
+namespace crypto::apple {
+
+static KeychainV2* g_keychain_instance_override = nullptr;
+
+// static
+KeychainV2& KeychainV2::GetInstance() {
+  if (g_keychain_instance_override) {
+    return *g_keychain_instance_override;
+  }
+  static base::NoDestructor<KeychainV2> k;
+  return *k;
+}
+
+// static
+void KeychainV2::SetInstanceOverride(KeychainV2* KeychainV2) {
+  CHECK(!g_keychain_instance_override);
+  g_keychain_instance_override = KeychainV2;
+}
+
+// static
+void KeychainV2::ClearInstanceOverride() {
+  CHECK(g_keychain_instance_override);
+  g_keychain_instance_override = nullptr;
+}
+
+KeychainV2::KeychainV2() = default;
+KeychainV2::~KeychainV2() = default;
+
+NSArray* KeychainV2::GetTokenIDs() {
+  return [[TKTokenWatcher alloc] init].tokenIDs;
+}
+
+base::apple::ScopedCFTypeRef<SecKeyRef> KeychainV2::KeyCreateRandomKey(
+    CFDictionaryRef params,
+    CFErrorRef* error) {
+  return base::apple::ScopedCFTypeRef<SecKeyRef>(
+      SecKeyCreateRandomKey(params, error));
+}
+
+base::apple::ScopedCFTypeRef<CFDataRef> KeychainV2::KeyCreateSignature(
+    SecKeyRef key,
+    SecKeyAlgorithm algorithm,
+    CFDataRef data,
+    CFErrorRef* error) {
+  return base::apple::ScopedCFTypeRef<CFDataRef>(
+      SecKeyCreateSignature(key, algorithm, data, error));
+}
+
+base::apple::ScopedCFTypeRef<SecKeyRef> KeychainV2::KeyCopyPublicKey(
+    SecKeyRef key) {
+  return base::apple::ScopedCFTypeRef<SecKeyRef>(SecKeyCopyPublicKey(key));
+}
+
+base::apple::ScopedCFTypeRef<CFDataRef>
+KeychainV2::KeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef* error) {
+  return base::apple::ScopedCFTypeRef<CFDataRef>(
+      SecKeyCopyExternalRepresentation(key, error));
+}
+
+base::apple::ScopedCFTypeRef<CFDictionaryRef> KeychainV2::KeyCopyAttributes(
+    SecKeyRef key) {
+  return base::apple::ScopedCFTypeRef<CFDictionaryRef>(
+      SecKeyCopyAttributes(key));
+}
+
+OSStatus KeychainV2::ItemAdd(CFDictionaryRef attributes, CFTypeRef* result) {
+  return SecItemAdd(attributes, result);
+}
+
+OSStatus KeychainV2::ItemCopyMatching(CFDictionaryRef query,
+                                      CFTypeRef* result) {
+  return SecItemCopyMatching(query, result);
+}
+
+OSStatus KeychainV2::ItemDelete(CFDictionaryRef query) {
+  return SecItemDelete(query);
+}
+
+OSStatus KeychainV2::ItemUpdate(CFDictionaryRef query,
+                                CFDictionaryRef keychain_data) {
+  return SecItemUpdate(query, keychain_data);
+}
+
+#if !BUILDFLAG(IS_IOS)
+base::apple::ScopedCFTypeRef<CFTypeRef> KeychainV2::TaskCopyValueForEntitlement(
+    SecTaskRef task,
+    CFStringRef entitlement,
+    CFErrorRef* error) {
+  return base::apple::ScopedCFTypeRef<CFTypeRef>(
+      SecTaskCopyValueForEntitlement(task, entitlement, error));
+}
+#endif  // !BUILDFLAG(IS_IOS)
+
+#if !BUILDFLAG(IS_IOS_TVOS)
+BOOL KeychainV2::LAContextCanEvaluatePolicy(LAPolicy policy, NSError** error) {
+  LAContext* context = [[LAContext alloc] init];
+  return [context canEvaluatePolicy:policy error:error];
+}
+#endif  // !BUILDFLAG(IS_IOS_TVOS)
+
+}  // namespace crypto::apple
diff --git a/crypto/mock_apple_keychain.cc b/crypto/apple/mock_keychain.cc
similarity index 68%
rename from crypto/mock_apple_keychain.cc
rename to crypto/apple/mock_keychain.cc
index d766dc4..080806a 100644
--- a/crypto/mock_apple_keychain.cc
+++ b/crypto/apple/mock_keychain.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 "crypto/mock_apple_keychain.h"
+#include "crypto/apple/mock_keychain.h"
 
 #include "base/check_op.h"
 #include "base/containers/span.h"
@@ -14,8 +14,8 @@
 
 constexpr char kPassword[] = "mock_password";
 
-// Adds an entry to a local histogram to indicate that the Apple Keychain would
-// have been accessed, if this class were not a mock of the Apple Keychain.
+// Adds an entry to a local histogram to indicate that the Keychain would have
+// been accessed, if this class were not a mock of the Keychain.
 void IncrementKeychainAccessHistogram() {
   // This local histogram is accessed by Telemetry to track the number of times
   // the keychain is accessed, since keychain access is known to be synchronous
@@ -25,14 +25,14 @@
 
 }  // namespace
 
-namespace crypto {
+namespace crypto::apple {
 
-MockAppleKeychain::MockAppleKeychain() = default;
-MockAppleKeychain::~MockAppleKeychain() = default;
+MockKeychain::MockKeychain() = default;
+MockKeychain::~MockKeychain() = default;
 
 base::expected<std::vector<uint8_t>, OSStatus>
-MockAppleKeychain::FindGenericPassword(std::string_view service_name,
-                                       std::string_view account_name) const {
+MockKeychain::FindGenericPassword(std::string_view service_name,
+                                  std::string_view account_name) const {
   IncrementKeychainAccessHistogram();
 
   // When simulating |noErr|, return canned |passwordData| and
@@ -44,7 +44,7 @@
   return base::unexpected(find_generic_result_);
 }
 
-OSStatus MockAppleKeychain::AddGenericPassword(
+OSStatus MockKeychain::AddGenericPassword(
     std::string_view service_name,
     std::string_view account_name,
     base::span<const uint8_t> password) const {
@@ -56,9 +56,9 @@
   return noErr;
 }
 
-std::string MockAppleKeychain::GetEncryptionPassword() const {
+std::string MockKeychain::GetEncryptionPassword() const {
   IncrementKeychainAccessHistogram();
   return kPassword;
 }
 
-}  // namespace crypto
+}  // namespace crypto::apple
diff --git a/crypto/mock_apple_keychain.h b/crypto/apple/mock_keychain.h
similarity index 72%
rename from crypto/mock_apple_keychain.h
rename to crypto/apple/mock_keychain.h
index fd903e64..40fb4e1f 100644
--- a/crypto/mock_apple_keychain.h
+++ b/crypto/apple/mock_keychain.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 CRYPTO_MOCK_APPLE_KEYCHAIN_H_
-#define CRYPTO_MOCK_APPLE_KEYCHAIN_H_
+#ifndef CRYPTO_APPLE_MOCK_KEYCHAIN_H_
+#define CRYPTO_APPLE_MOCK_KEYCHAIN_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -15,27 +15,26 @@
 
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
-#include "crypto/apple_keychain.h"
+#include "crypto/apple/keychain.h"
 
-namespace crypto {
+namespace crypto::apple {
 
 // Mock Keychain wrapper for testing code that interacts with the OS X
 // Keychain.
 //
 // Note that "const" is pretty much meaningless for this class; the const-ness
-// of AppleKeychain doesn't apply to the actual keychain data, so all of the
-// Mock data is mutable; don't assume that it won't change over the life of
-// tests.
-class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain {
+// of Keychain doesn't apply to the actual keychain data, so all of the Mock
+// data is mutable; don't assume that it won't change over the life of tests.
+class CRYPTO_EXPORT MockKeychain : public Keychain {
  public:
-  MockAppleKeychain();
+  MockKeychain();
 
-  MockAppleKeychain(const MockAppleKeychain&) = delete;
-  MockAppleKeychain& operator=(const MockAppleKeychain&) = delete;
+  MockKeychain(const MockKeychain&) = delete;
+  MockKeychain& operator=(const MockKeychain&) = delete;
 
-  ~MockAppleKeychain() override;
+  ~MockKeychain() override;
 
-  // AppleKeychain implementation.
+  // Keychain implementation.
   base::expected<std::vector<uint8_t>, OSStatus> FindGenericPassword(
       std::string_view service_name,
       std::string_view account_name) const override;
@@ -68,6 +67,6 @@
   mutable bool called_add_generic_ = false;
 };
 
-}  // namespace crypto
+}  // namespace crypto::apple
 
-#endif  // CRYPTO_MOCK_APPLE_KEYCHAIN_H_
+#endif  // CRYPTO_APPLE_MOCK_KEYCHAIN_H_
diff --git a/crypto/mock_apple_keychain_unittest.cc b/crypto/apple/mock_keychain_unittest.cc
similarity index 80%
rename from crypto/mock_apple_keychain_unittest.cc
rename to crypto/apple/mock_keychain_unittest.cc
index f833056..8caa903 100644
--- a/crypto/mock_apple_keychain_unittest.cc
+++ b/crypto/apple/mock_keychain_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "crypto/mock_apple_keychain.h"
+#include "crypto/apple/mock_keychain.h"
 
 #include <string>
 
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(MockAppleKeychain, Basic) {
-  crypto::MockAppleKeychain keychain;
+  crypto::apple::MockKeychain keychain;
   const auto password = keychain.GetEncryptionPassword();
   ASSERT_FALSE(password.empty());
 }
diff --git a/crypto/apple/scoped_fake_keychain_v2.h b/crypto/apple/scoped_fake_keychain_v2.h
new file mode 100644
index 0000000..7987b61
--- /dev/null
+++ b/crypto/apple/scoped_fake_keychain_v2.h
@@ -0,0 +1,42 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_APPLE_SCOPED_FAKE_KEYCHAIN_V2_H_
+#define CRYPTO_APPLE_SCOPED_FAKE_KEYCHAIN_V2_H_
+
+#include <memory>
+#include <string>
+
+#include "crypto/crypto_export.h"
+
+namespace crypto::apple {
+
+class FakeKeychainV2;
+
+// ScopedFakeKeychainV2 installs itself as testing override for
+// `KeychainV2::GetInstance()`.
+class CRYPTO_EXPORT ScopedFakeKeychainV2 {
+ public:
+  // Supported types of user verification, reported by
+  // LAContextCanEvaluatePolicy.
+  enum class UVMethod {
+    kNone,
+    kPasswordOnly,
+    kBiometrics,
+  };
+
+  explicit ScopedFakeKeychainV2(const std::string& keychain_access_group);
+  ~ScopedFakeKeychainV2();
+
+  FakeKeychainV2* keychain() { return keychain_.get(); }
+
+  void SetUVMethod(UVMethod uv_method);
+
+ private:
+  std::unique_ptr<FakeKeychainV2> keychain_;
+};
+
+}  // namespace crypto::apple
+
+#endif  // CRYPTO_APPLE_SCOPED_FAKE_KEYCHAIN_V2_H_
diff --git a/crypto/apple/scoped_fake_keychain_v2.mm b/crypto/apple/scoped_fake_keychain_v2.mm
new file mode 100644
index 0000000..a6c7e29b
--- /dev/null
+++ b/crypto/apple/scoped_fake_keychain_v2.mm
@@ -0,0 +1,27 @@
+// 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 "crypto/apple/scoped_fake_keychain_v2.h"
+
+#include <memory>
+
+#include "crypto/apple/fake_keychain_v2.h"
+
+namespace crypto::apple {
+
+ScopedFakeKeychainV2::ScopedFakeKeychainV2(
+    const std::string& keychain_access_group)
+    : keychain_(std::make_unique<FakeKeychainV2>(keychain_access_group)) {
+  KeychainV2::SetInstanceOverride(keychain_.get());
+}
+
+ScopedFakeKeychainV2::~ScopedFakeKeychainV2() {
+  KeychainV2::ClearInstanceOverride();
+}
+
+void ScopedFakeKeychainV2::SetUVMethod(UVMethod uv_method) {
+  keychain_->set_uv_method(uv_method);
+}
+
+}  // namespace crypto::apple
diff --git a/crypto/apple_keychain_v2.mm b/crypto/apple_keychain_v2.mm
deleted file mode 100644
index bb599d1..0000000
--- a/crypto/apple_keychain_v2.mm
+++ /dev/null
@@ -1,116 +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 <CryptoTokenKit/CryptoTokenKit.h>
-#import <Foundation/Foundation.h>
-
-#include "crypto/apple_keychain_v2.h"
-#include "base/apple/foundation_util.h"
-#include "base/apple/scoped_cftyperef.h"
-#include "base/no_destructor.h"
-
-namespace crypto {
-
-static AppleKeychainV2* g_keychain_instance_override = nullptr;
-
-// static
-AppleKeychainV2& AppleKeychainV2::GetInstance() {
-  if (g_keychain_instance_override) {
-    return *g_keychain_instance_override;
-  }
-  static base::NoDestructor<AppleKeychainV2> k;
-  return *k;
-}
-
-// static
-void AppleKeychainV2::SetInstanceOverride(AppleKeychainV2* AppleKeychainV2) {
-  CHECK(!g_keychain_instance_override);
-  g_keychain_instance_override = AppleKeychainV2;
-}
-
-// static
-void AppleKeychainV2::ClearInstanceOverride() {
-  CHECK(g_keychain_instance_override);
-  g_keychain_instance_override = nullptr;
-}
-
-AppleKeychainV2::AppleKeychainV2() = default;
-AppleKeychainV2::~AppleKeychainV2() = default;
-
-NSArray* AppleKeychainV2::GetTokenIDs() {
-  return [[TKTokenWatcher alloc] init].tokenIDs;
-}
-
-base::apple::ScopedCFTypeRef<SecKeyRef> AppleKeychainV2::KeyCreateRandomKey(
-    CFDictionaryRef params,
-    CFErrorRef* error) {
-  return base::apple::ScopedCFTypeRef<SecKeyRef>(
-      SecKeyCreateRandomKey(params, error));
-}
-
-base::apple::ScopedCFTypeRef<CFDataRef> AppleKeychainV2::KeyCreateSignature(
-    SecKeyRef key,
-    SecKeyAlgorithm algorithm,
-    CFDataRef data,
-    CFErrorRef* error) {
-  return base::apple::ScopedCFTypeRef<CFDataRef>(
-      SecKeyCreateSignature(key, algorithm, data, error));
-}
-
-base::apple::ScopedCFTypeRef<SecKeyRef> AppleKeychainV2::KeyCopyPublicKey(
-    SecKeyRef key) {
-  return base::apple::ScopedCFTypeRef<SecKeyRef>(SecKeyCopyPublicKey(key));
-}
-
-base::apple::ScopedCFTypeRef<CFDataRef>
-AppleKeychainV2::KeyCopyExternalRepresentation(SecKeyRef key,
-                                               CFErrorRef* error) {
-  return base::apple::ScopedCFTypeRef<CFDataRef>(
-      SecKeyCopyExternalRepresentation(key, error));
-}
-
-base::apple::ScopedCFTypeRef<CFDictionaryRef>
-AppleKeychainV2::KeyCopyAttributes(SecKeyRef key) {
-  return base::apple::ScopedCFTypeRef<CFDictionaryRef>(
-      SecKeyCopyAttributes(key));
-}
-
-OSStatus AppleKeychainV2::ItemAdd(CFDictionaryRef attributes,
-                                  CFTypeRef* result) {
-  return SecItemAdd(attributes, result);
-}
-
-OSStatus AppleKeychainV2::ItemCopyMatching(
-    CFDictionaryRef query, CFTypeRef* result) {
-  return SecItemCopyMatching(query, result);
-}
-
-OSStatus AppleKeychainV2::ItemDelete(CFDictionaryRef query) {
-  return SecItemDelete(query);
-}
-
-OSStatus AppleKeychainV2::ItemUpdate(CFDictionaryRef query,
-                                     CFDictionaryRef keychain_data) {
-  return SecItemUpdate(query, keychain_data);
-}
-
-#if !BUILDFLAG(IS_IOS)
-base::apple::ScopedCFTypeRef<CFTypeRef>
-AppleKeychainV2::TaskCopyValueForEntitlement(SecTaskRef task,
-                                             CFStringRef entitlement,
-                                             CFErrorRef* error) {
-  return base::apple::ScopedCFTypeRef<CFTypeRef>(
-      SecTaskCopyValueForEntitlement(task, entitlement, error));
-}
-#endif  // !BUILDFLAG(IS_IOS)
-
-#if !BUILDFLAG(IS_IOS_TVOS)
-BOOL AppleKeychainV2::LAContextCanEvaluatePolicy(LAPolicy policy,
-                                                 NSError** error) {
-  LAContext* context = [[LAContext alloc] init];
-  return [context canEvaluatePolicy:policy error:error];
-}
-#endif  // !BUILDFLAG(IS_IOS_TVOS)
-
-}  // namespace crypto
diff --git a/crypto/hash.cc b/crypto/hash.cc
index 60a6b1b..e379d4c 100644
--- a/crypto/hash.cc
+++ b/crypto/hash.cc
@@ -14,25 +14,6 @@
 
 namespace crypto::hash {
 
-namespace {
-
-// TODO(https://issues.chromium.org/issues/430635196): Deduplicate.
-const EVP_MD* EVPMDForHashKind(HashKind kind) {
-  switch (kind) {
-    case HashKind::kSha1:
-      return EVP_sha1();
-    case HashKind::kSha256:
-      return EVP_sha256();
-    case HashKind::kSha384:
-      return EVP_sha384();
-    case HashKind::kSha512:
-      return EVP_sha512();
-  }
-  NOTREACHED();
-}
-
-}  // namespace
-
 void Hash(HashKind kind,
           base::span<const uint8_t> data,
           base::span<uint8_t> digest) {
@@ -77,6 +58,34 @@
   return Sha512(base::as_byte_span(data));
 }
 
+const EVP_MD* EVPMDForHashKind(HashKind kind) {
+  switch (kind) {
+    case HashKind::kSha1:
+      return EVP_sha1();
+    case HashKind::kSha256:
+      return EVP_sha256();
+    case HashKind::kSha384:
+      return EVP_sha384();
+    case HashKind::kSha512:
+      return EVP_sha512();
+  }
+  NOTREACHED();
+}
+
+std::optional<HashKind> HashKindForEVPMD(const EVP_MD* evp_md) {
+  switch (EVP_MD_type(evp_md)) {
+    case NID_sha1:
+      return crypto::hash::kSha1;
+    case NID_sha256:
+      return crypto::hash::kSha256;
+    case NID_sha384:
+      return crypto::hash::kSha384;
+    case NID_sha512:
+      return crypto::hash::kSha512;
+  }
+  return std::nullopt;
+}
+
 Hasher::Hasher(HashKind kind) {
   CHECK(EVP_DigestInit(ctx_.get(), EVPMDForHashKind(kind)));
 }
diff --git a/crypto/hash.h b/crypto/hash.h
index ca944e815..4b62cd3f 100644
--- a/crypto/hash.h
+++ b/crypto/hash.h
@@ -13,6 +13,7 @@
 #include "base/containers/span.h"
 #include "base/notreached.h"
 #include "crypto/crypto_export.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
 #include "third_party/boringssl/src/include/openssl/digest.h"
 
 namespace crypto::hash {
@@ -45,6 +46,13 @@
   kSha512,
 };
 
+// Free functions to convert to/from bssl EVP_MDs. The functions to convert to
+// HashKind return optionals because HashKind can only represent a subset of the
+// algorithms BoringSSL supports - specifically the ones the //crypto OWNERS
+// recommend people use.
+CRYPTO_EXPORT const EVP_MD* EVPMDForHashKind(HashKind k);
+CRYPTO_EXPORT std::optional<HashKind> HashKindForEVPMD(const EVP_MD* evp_md);
+
 inline constexpr size_t DigestSizeForHashKind(HashKind k) {
   switch (k) {
     case kSha1:
diff --git a/crypto/hash_unittest.cc b/crypto/hash_unittest.cc
index 2efdc3d..ccdf364 100644
--- a/crypto/hash_unittest.cc
+++ b/crypto/hash_unittest.cc
@@ -129,3 +129,19 @@
       0x0a, 0x4b, 0x28, 0x68, 0x8a, 0x36, 0x21, 0x82, 0x98, 0x6f};
   EXPECT_EQ(hash, crypto::hash::Sha256("Hello, World!"));
 }
+
+TEST(HashTest, HashKindEVPMDConversions) {
+  constexpr auto kKinds = std::to_array<crypto::hash::HashKind>({
+      crypto::hash::kSha1,
+      crypto::hash::kSha256,
+      crypto::hash::kSha384,
+      crypto::hash::kSha512,
+  });
+  for (auto kind : kKinds) {
+    const EVP_MD* md = crypto::hash::EVPMDForHashKind(kind);
+    auto result_kind = crypto::hash::HashKindForEVPMD(md);
+    ASSERT_TRUE(result_kind.has_value());
+    EXPECT_EQ(kind, *result_kind);
+  }
+  EXPECT_FALSE(crypto::hash::HashKindForEVPMD(EVP_md5()).has_value());
+}
diff --git a/crypto/hmac.cc b/crypto/hmac.cc
index 72d918e6..d5b65f5 100644
--- a/crypto/hmac.cc
+++ b/crypto/hmac.cc
@@ -110,34 +110,15 @@
 
 namespace hmac {
 
-namespace {
-
-const EVP_MD* EVPMDForHashKind(crypto::hash::HashKind kind) {
-  switch (kind) {
-    case crypto::hash::HashKind::kSha1:
-      return EVP_sha1();
-    case crypto::hash::HashKind::kSha256:
-      return EVP_sha256();
-    case crypto::hash::HashKind::kSha384:
-      return EVP_sha384();
-    case crypto::hash::HashKind::kSha512:
-      return EVP_sha512();
-  }
-  NOTREACHED();
-}
-
-}  // namespace
-
 void Sign(crypto::hash::HashKind kind,
           base::span<const uint8_t> key,
           base::span<const uint8_t> data,
           base::span<uint8_t> hmac) {
-  const EVP_MD* md = EVPMDForHashKind(kind);
+  const EVP_MD* md = crypto::hash::EVPMDForHashKind(kind);
   CHECK_EQ(hmac.size(), EVP_MD_size(md));
 
   bssl::ScopedHMAC_CTX ctx;
-  CHECK(HMAC_Init_ex(ctx.get(), key.data(), key.size(), EVPMDForHashKind(kind),
-                     nullptr));
+  CHECK(HMAC_Init_ex(ctx.get(), key.data(), key.size(), md, nullptr));
   CHECK(HMAC_Update(ctx.get(), data.data(), data.size()));
   CHECK(HMAC_Final(ctx.get(), hmac.data(), nullptr));
 }
@@ -146,7 +127,7 @@
             base::span<const uint8_t> key,
             base::span<const uint8_t> data,
             base::span<const uint8_t> hmac) {
-  const EVP_MD* md = EVPMDForHashKind(kind);
+  const EVP_MD* md = crypto::hash::EVPMDForHashKind(kind);
   CHECK_EQ(hmac.size(), EVP_MD_size(md));
 
   std::array<uint8_t, EVP_MAX_MD_SIZE> computed_buf;
diff --git a/crypto/kdf.cc b/crypto/kdf.cc
index afcc0292..6f0544d 100644
--- a/crypto/kdf.cc
+++ b/crypto/kdf.cc
@@ -11,26 +11,6 @@
 
 namespace crypto::kdf {
 
-namespace {
-
-// Duplicated from crypto/hash
-// TODO(https://issues.chromium.org/issues/430635196): Deduplicate.
-const EVP_MD* EVPMDForHashKind(crypto::hash::HashKind kind) {
-  switch (kind) {
-    case crypto::hash::HashKind::kSha1:
-      return EVP_sha1();
-    case crypto::hash::HashKind::kSha256:
-      return EVP_sha256();
-    case crypto::hash::HashKind::kSha384:
-      return EVP_sha384();
-    case crypto::hash::HashKind::kSha512:
-      return EVP_sha512();
-  }
-  NOTREACHED();
-}
-
-}  // namespace
-
 void DeriveKeyPbkdf2HmacSha1(const Pbkdf2HmacSha1Params& params,
                              base::span<const uint8_t> password,
                              base::span<const uint8_t> salt,
@@ -66,11 +46,11 @@
           base::span<uint8_t> out) {
   // Even though ::HKDF() will fail in this situation, check it explicitly here
   // to give better error info:
-  CHECK_LT(out.size(), 255 * DigestSizeForHashKind(kind));
-  CHECK_EQ(
-      ::HKDF(out.data(), out.size(), EVPMDForHashKind(kind), secret.data(),
-             secret.size(), salt.data(), salt.size(), info.data(), info.size()),
-      1);
+  CHECK_LT(out.size(), 255 * crypto::hash::DigestSizeForHashKind(kind));
+  CHECK_EQ(::HKDF(out.data(), out.size(), crypto::hash::EVPMDForHashKind(kind),
+                  secret.data(), secret.size(), salt.data(), salt.size(),
+                  info.data(), info.size()),
+           1);
 }
 
 }  // namespace crypto::kdf
diff --git a/crypto/rsa_private_key.cc b/crypto/rsa_private_key.cc
index bd53bab..88d1bd9f 100644
--- a/crypto/rsa_private_key.cc
+++ b/crypto/rsa_private_key.cc
@@ -26,26 +26,6 @@
 namespace crypto {
 
 // static
-std::unique_ptr<RSAPrivateKey> RSAPrivateKey::Create(uint16_t num_bits) {
-  OpenSSLErrStackTracer err_tracer(FROM_HERE);
-
-  bssl::UniquePtr<RSA> rsa_key(RSA_new());
-  bssl::UniquePtr<BIGNUM> bn(BN_new());
-  if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L))
-    return nullptr;
-
-  if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), nullptr))
-    return nullptr;
-
-  std::unique_ptr<RSAPrivateKey> result(new RSAPrivateKey);
-  result->key_.reset(EVP_PKEY_new());
-  if (!result->key_ || !EVP_PKEY_set1_RSA(result->key_.get(), rsa_key.get()))
-    return nullptr;
-
-  return result;
-}
-
-// static
 std::unique_ptr<RSAPrivateKey> RSAPrivateKey::CreateFromPrivateKeyInfo(
     base::span<const uint8_t> input) {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
@@ -61,16 +41,6 @@
   return result;
 }
 
-// static
-std::unique_ptr<RSAPrivateKey> RSAPrivateKey::CreateFromKey(EVP_PKEY* key) {
-  DCHECK(key);
-  if (EVP_PKEY_id(key) != EVP_PKEY_RSA)
-    return nullptr;
-  std::unique_ptr<RSAPrivateKey> copy(new RSAPrivateKey);
-  copy->key_ = bssl::UpRef(key);
-  return copy;
-}
-
 RSAPrivateKey::RSAPrivateKey() = default;
 
 RSAPrivateKey::~RSAPrivateKey() = default;
diff --git a/crypto/rsa_private_key.h b/crypto/rsa_private_key.h
index c85ed44..b5f88c5 100644
--- a/crypto/rsa_private_key.h
+++ b/crypto/rsa_private_key.h
@@ -21,8 +21,8 @@
 
 namespace crypto {
 
-// Encapsulates an RSA private key. Can be used to generate new keys, export
-// keys to other formats, or to extract a public key.
+// Encapsulates an RSA private key. Can be used to export keys to other formats
+// or to extract a public key.
 // TODO(https://crbug.com/425863216): Delete this.
 class CRYPTO_EXPORT RSAPrivateKey {
  public:
@@ -31,20 +31,12 @@
 
   ~RSAPrivateKey();
 
-  // Create a new random instance. Can return NULL if initialization fails.
-  static std::unique_ptr<RSAPrivateKey> Create(uint16_t num_bits);
-
   // Create a new instance by importing an existing private key. The format is
   // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if
   // initialization fails.
   static std::unique_ptr<RSAPrivateKey> CreateFromPrivateKeyInfo(
       base::span<const uint8_t> input);
 
-  // Create a new instance from an existing EVP_PKEY, taking a
-  // reference to it. |key| must be an RSA key. Returns NULL on
-  // failure.
-  static std::unique_ptr<RSAPrivateKey> CreateFromKey(EVP_PKEY* key);
-
   EVP_PKEY* key() const { return key_.get(); }
 
   // Creates a copy of the object.
diff --git a/crypto/rsa_private_key_unittest.cc b/crypto/rsa_private_key_unittest.cc
index bf414f6..97b160ea 100644
--- a/crypto/rsa_private_key_unittest.cc
+++ b/crypto/rsa_private_key_unittest.cc
@@ -74,44 +74,6 @@
 
 }  // namespace
 
-// Generate random private keys with two different sizes. Reimport, then
-// export them again. We should get back the same exact bytes.
-TEST(RSAPrivateKeyUnitTest, InitRandomTest) {
-  std::unique_ptr<crypto::RSAPrivateKey> keypair1(
-      crypto::RSAPrivateKey::Create(1024));
-  std::unique_ptr<crypto::RSAPrivateKey> keypair2(
-      crypto::RSAPrivateKey::Create(2048));
-  ASSERT_TRUE(keypair1.get());
-  ASSERT_TRUE(keypair2.get());
-
-  std::vector<uint8_t> privkey1;
-  std::vector<uint8_t> privkey2;
-  std::vector<uint8_t> pubkey1;
-  std::vector<uint8_t> pubkey2;
-
-  ASSERT_TRUE(keypair1->ExportPrivateKey(&privkey1));
-  ASSERT_TRUE(keypair2->ExportPrivateKey(&privkey2));
-  ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1));
-  ASSERT_TRUE(keypair2->ExportPublicKey(&pubkey2));
-
-  std::unique_ptr<crypto::RSAPrivateKey> keypair3(
-      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey1));
-  std::unique_ptr<crypto::RSAPrivateKey> keypair4(
-      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey2));
-  ASSERT_TRUE(keypair3.get());
-  ASSERT_TRUE(keypair4.get());
-
-  std::vector<uint8_t> privkey3;
-  std::vector<uint8_t> privkey4;
-  ASSERT_TRUE(keypair3->ExportPrivateKey(&privkey3));
-  ASSERT_TRUE(keypair4->ExportPrivateKey(&privkey4));
-
-  ASSERT_EQ(privkey1.size(), privkey3.size());
-  ASSERT_EQ(privkey2.size(), privkey4.size());
-  ASSERT_EQ(0, memcmp(&privkey1.front(), &privkey3.front(), privkey1.size()));
-  ASSERT_EQ(0, memcmp(&privkey2.front(), &privkey4.front(), privkey2.size()));
-}
-
 // Test Copy() method.
 TEST(RSAPrivateKeyUnitTest, CopyTest) {
   std::vector<uint8_t> input(kTestPrivateKeyInfo,
@@ -355,27 +317,3 @@
   ASSERT_EQ(0, memcmp(&output1.front(), &input1.front(), input1.size()));
   ASSERT_EQ(0, memcmp(&output2.front(), &input2.front(), input2.size()));
 }
-
-TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) {
-  std::unique_ptr<crypto::RSAPrivateKey> key_pair(
-      crypto::RSAPrivateKey::Create(2048));
-  ASSERT_TRUE(key_pair.get());
-
-  std::unique_ptr<crypto::RSAPrivateKey> key_copy(
-      crypto::RSAPrivateKey::CreateFromKey(key_pair->key()));
-  ASSERT_TRUE(key_copy.get());
-
-  std::vector<uint8_t> privkey;
-  std::vector<uint8_t> pubkey;
-  ASSERT_TRUE(key_pair->ExportPrivateKey(&privkey));
-  ASSERT_TRUE(key_pair->ExportPublicKey(&pubkey));
-
-  std::vector<uint8_t> privkey_copy;
-  std::vector<uint8_t> pubkey_copy;
-  ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy));
-  ASSERT_TRUE(key_copy->ExportPublicKey(&pubkey_copy));
-
-  ASSERT_EQ(privkey, privkey_copy);
-  ASSERT_EQ(pubkey, pubkey_copy);
-}
-
diff --git a/crypto/scoped_fake_apple_keychain_v2.h b/crypto/scoped_fake_apple_keychain_v2.h
deleted file mode 100644
index b4d3785..0000000
--- a/crypto/scoped_fake_apple_keychain_v2.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CRYPTO_SCOPED_FAKE_APPLE_KEYCHAIN_V2_H_
-#define CRYPTO_SCOPED_FAKE_APPLE_KEYCHAIN_V2_H_
-
-#include <memory>
-#include <string>
-
-#include "crypto/crypto_export.h"
-
-namespace crypto {
-
-class FakeAppleKeychainV2;
-
-// ScopedFakeAppleKeychainV2 installs itself as testing override for
-// `AppleKeychainV2::GetInstance()`.
-class CRYPTO_EXPORT ScopedFakeAppleKeychainV2 {
- public:
-  // Supported types of user verification, reported by
-  // LAContextCanEvaluatePolicy.
-  enum class UVMethod {
-    kNone,
-    kPasswordOnly,
-    kBiometrics,
-  };
-
-  explicit ScopedFakeAppleKeychainV2(const std::string& keychain_access_group);
-  ~ScopedFakeAppleKeychainV2();
-
-  FakeAppleKeychainV2* keychain() { return keychain_.get(); }
-
-  void SetUVMethod(UVMethod uv_method);
-
- private:
-  std::unique_ptr<FakeAppleKeychainV2> keychain_;
-};
-
-}  // namespace crypto
-
-#endif  // CRYPTO_SCOPED_FAKE_APPLE_KEYCHAIN_V2_H_
diff --git a/crypto/scoped_fake_apple_keychain_v2.mm b/crypto/scoped_fake_apple_keychain_v2.mm
deleted file mode 100644
index 2624311..0000000
--- a/crypto/scoped_fake_apple_keychain_v2.mm
+++ /dev/null
@@ -1,27 +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 "crypto/scoped_fake_apple_keychain_v2.h"
-
-#include <memory>
-
-#include "crypto/fake_apple_keychain_v2.h"
-
-namespace crypto {
-
-ScopedFakeAppleKeychainV2::ScopedFakeAppleKeychainV2(
-    const std::string& keychain_access_group)
-    : keychain_(std::make_unique<FakeAppleKeychainV2>(keychain_access_group)) {
-  AppleKeychainV2::SetInstanceOverride(keychain_.get());
-}
-
-ScopedFakeAppleKeychainV2::~ScopedFakeAppleKeychainV2() {
-  AppleKeychainV2::ClearInstanceOverride();
-}
-
-void ScopedFakeAppleKeychainV2::SetUVMethod(UVMethod uv_method) {
-  keychain_->set_uv_method(uv_method);
-}
-
-}  // namespace crypto
diff --git a/crypto/unexportable_key_mac.mm b/crypto/unexportable_key_mac.mm
index 750ce17b..ad232ac 100644
--- a/crypto/unexportable_key_mac.mm
+++ b/crypto/unexportable_key_mac.mm
@@ -34,8 +34,8 @@
 #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/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"
@@ -130,9 +130,9 @@
                 key_attributes,
                 kSecAttrApplicationLabel))) {
     base::apple::ScopedCFTypeRef<SecKeyRef> public_key(
-        AppleKeychainV2::GetInstance().KeyCopyPublicKey(key_.get()));
+        crypto::apple::KeychainV2::GetInstance().KeyCopyPublicKey(key_.get()));
     base::apple::ScopedCFTypeRef<CFDataRef> x962_bytes(
-        AppleKeychainV2::GetInstance().KeyCopyExternalRepresentation(
+        crypto::apple::KeychainV2::GetInstance().KeyCopyExternalRepresentation(
             public_key.get(), /*error=*/nil));
     CHECK(x962_bytes);
     base::span<const uint8_t> x962_span =
@@ -168,7 +168,7 @@
     NSData* nsdata = [NSData dataWithBytes:data.data() length:data.size()];
     base::apple::ScopedCFTypeRef<CFErrorRef> error;
     base::apple::ScopedCFTypeRef<CFDataRef> signature(
-        AppleKeychainV2::GetInstance().KeyCreateSignature(
+        crypto::apple::KeychainV2::GetInstance().KeyCreateSignature(
             key_.get(), algorithm, NSToCFPtrCast(nsdata),
             error.InitializeInto()));
     if (!signature) {
@@ -292,7 +292,7 @@
 
   base::apple::ScopedCFTypeRef<CFErrorRef> error;
   base::apple::ScopedCFTypeRef<SecKeyRef> private_key(
-      AppleKeychainV2::GetInstance().KeyCreateRandomKey(
+      crypto::apple::KeychainV2::GetInstance().KeyCreateRandomKey(
           NSToCFPtrCast(attributes), error.InitializeInto()));
   if (!private_key) {
     LOG(ERROR) << "Could not create private key: " << error.get();
@@ -300,7 +300,8 @@
     return nullptr;
   }
   base::apple::ScopedCFTypeRef<CFDictionaryRef> key_metadata =
-      AppleKeychainV2::GetInstance().KeyCopyAttributes(private_key.get());
+      crypto::apple::KeychainV2::GetInstance().KeyCopyAttributes(
+          private_key.get());
   return std::make_unique<UnexportableSigningKeyMac>(std::move(private_key),
                                                      key_metadata.get());
 }
@@ -330,7 +331,7 @@
   if (lacontext) {
     query[CFToNSPtrCast(kSecUseAuthenticationContext)] = lacontext;
   }
-  OSStatus status = AppleKeychainV2::GetInstance().ItemCopyMatching(
+  OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemCopyMatching(
       NSToCFPtrCast(query), key_data.InitializeInto());
   CFDictionaryRef key_attributes =
       base::apple::CFCast<CFDictionaryRef>(key_data.get());
@@ -360,7 +361,7 @@
         [NSData dataWithBytes:wrapped_key.data() length:wrapped_key.size()],
   };
   OSStatus result =
-      AppleKeychainV2::GetInstance().ItemDelete(NSToCFPtrCast(query));
+      crypto::apple::KeychainV2::GetInstance().ItemDelete(NSToCFPtrCast(query));
   return result == errSecSuccess;
 }
 
@@ -369,14 +370,14 @@
   CHECK(!config.keychain_access_group.empty())
       << "A keychain access group must be set when using unexportable keys on "
          "macOS";
-  if (![AppleKeychainV2::GetInstance().GetTokenIDs()
+  if (![crypto::apple::KeychainV2::GetInstance().GetTokenIDs()
           containsObject:CFToNSPtrCast(kSecAttrTokenIDSecureEnclave)]) {
     return nullptr;
   }
   // Inspecting the binary for the entitlement is not available on iOS, assume
   // it is available.
 #if !BUILDFLAG(IS_IOS)
-  if (!ExecutableHasKeychainAccessGroupEntitlement(
+  if (!crypto::apple::ExecutableHasKeychainAccessGroupEntitlement(
           config.keychain_access_group)) {
     return nullptr;
   }
diff --git a/crypto/unexportable_key_mac_unittest.mm b/crypto/unexportable_key_mac_unittest.mm
index b4a4f04..fec970a 100644
--- a/crypto/unexportable_key_mac_unittest.mm
+++ b/crypto/unexportable_key_mac_unittest.mm
@@ -4,8 +4,8 @@
 
 #include "crypto/unexportable_key.h"
 
-#include "crypto/fake_apple_keychain_v2.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "crypto/signature_verifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -25,14 +25,13 @@
 // keys.
 class UnexportableKeyMacTest : public testing::Test {
  protected:
-  ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_keychain_{
       kTestKeychainAccessGroup};
 };
 
 TEST_F(UnexportableKeyMacTest, SecureEnclaveAvailability) {
   for (bool available : {true, false}) {
-    scoped_fake_apple_keychain_.keychain()->set_secure_enclave_available(
-        available);
+    scoped_fake_keychain_.keychain()->set_secure_enclave_available(available);
     EXPECT_EQ(GetUnexportableKeyProvider(config) != nullptr, available);
   }
 }
@@ -46,7 +45,7 @@
   ASSERT_TRUE(provider->FromWrappedSigningKeySlowly(key->GetWrappedKey()));
   EXPECT_TRUE(provider->DeleteSigningKeySlowly(key->GetWrappedKey()));
   EXPECT_FALSE(provider->FromWrappedSigningKeySlowly(key->GetWrappedKey()));
-  EXPECT_TRUE(scoped_fake_apple_keychain_.keychain()->items().empty());
+  EXPECT_TRUE(scoped_fake_keychain_.keychain()->items().empty());
 }
 
 TEST_F(UnexportableKeyMacTest, DeleteUnknownSigningKey) {
diff --git a/crypto/unexportable_key_unittest.cc b/crypto/unexportable_key_unittest.cc
index 0e0e89a8..5f6c9c6 100644
--- a/crypto/unexportable_key_unittest.cc
+++ b/crypto/unexportable_key_unittest.cc
@@ -16,7 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_MAC)
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #endif  // BUILDFLAG(IS_MAC)
 
 #if BUILDFLAG(IS_WIN)
@@ -94,7 +94,7 @@
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 #if BUILDFLAG(IS_MAC)
-  crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_keychain_{
       kTestKeychainAccessGroup};
 #endif  // BUILDFLAG(IS_MAC)
 };
diff --git a/crypto/user_verifying_key_mac.mm b/crypto/user_verifying_key_mac.mm
index 06509149..900b3c0 100644
--- a/crypto/user_verifying_key_mac.mm
+++ b/crypto/user_verifying_key_mac.mm
@@ -21,7 +21,7 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/scoped_thread_priority.h"
 #include "base/types/expected.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 #include "crypto/scoped_lacontext.h"
 #include "crypto/unexportable_key.h"
 #include "crypto/unexportable_key_mac.h"
@@ -239,7 +239,7 @@
     return;
   }
   std::move(callback).Run(
-      AppleKeychainV2::GetInstance().LAContextCanEvaluatePolicy(
+      crypto::apple::KeychainV2::GetInstance().LAContextCanEvaluatePolicy(
           LAPolicyDeviceOwnerAuthentication, /*error=*/nil));
 }
 
diff --git a/crypto/user_verifying_key_mac_unittest.mm b/crypto/user_verifying_key_mac_unittest.mm
index 405bf217..f132090 100644
--- a/crypto/user_verifying_key_mac_unittest.mm
+++ b/crypto/user_verifying_key_mac_unittest.mm
@@ -4,18 +4,18 @@
 
 #include "crypto/user_verifying_key.h"
 
+#include <LocalAuthentication/LocalAuthentication.h>
+
 #include <iterator>
 #include <memory>
 
-#include <LocalAuthentication/LocalAuthentication.h>
-
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
-#include "crypto/fake_apple_keychain_v2.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "crypto/scoped_lacontext.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -100,7 +100,7 @@
   }
 
  protected:
-  ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_apple_keychain_{
       kTestKeychainAccessGroup};
 
   base::test::TaskEnvironment task_environment_;
@@ -148,7 +148,7 @@
 }
 
 TEST_F(UserVerifyingKeyMacTest, SecureEnclaveAvailability) {
-  using UVMethod = FakeAppleKeychainV2::UVMethod;
+  using UVMethod = crypto::apple::FakeKeychainV2::UVMethod;
   struct {
     bool enclave_available;
     UVMethod uv_method;
diff --git a/device/bluetooth/bluetooth_socket_android.cc b/device/bluetooth/bluetooth_socket_android.cc
index 53f6203..eb689bd 100644
--- a/device/bluetooth/bluetooth_socket_android.cc
+++ b/device/bluetooth/bluetooth_socket_android.cc
@@ -162,7 +162,7 @@
     return;
   }
 
-  base::android::ScopedJavaLocalRef<jbyteArray> j_buffer(
+  auto j_buffer = base::android::ScopedJavaLocalRef<jbyteArray>::Adopt(
       env, env->NewByteArray(buffer_size));
   base::android::CheckException(env);
   CHECK(j_buffer.obj());
diff --git a/device/fido/mac/authenticator_unittest.mm b/device/fido/mac/authenticator_unittest.mm
index 4cd0e49..b3b6601ca 100644
--- a/device/fido/mac/authenticator_unittest.mm
+++ b/device/fido/mac/authenticator_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "base/test/with_feature_override.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/authenticator_get_assertion_response.h"
 #include "device/fido/ctap_get_assertion_request.h"
 #include "device/fido/discoverable_credential_metadata.h"
@@ -43,7 +43,7 @@
   fido::mac::AuthenticatorConfig config_{
       .keychain_access_group = "test-keychain-access-group",
       .metadata_secret = "TestMetadataSecret"};
-  crypto::ScopedFakeAppleKeychainV2 keychain_{config_.keychain_access_group};
+  crypto::apple::ScopedFakeKeychainV2 keychain_{config_.keychain_access_group};
   fido::mac::TouchIdCredentialStore store_{config_};
 
   std::unique_ptr<fido::mac::TouchIdAuthenticator> authenticator_ =
diff --git a/device/fido/mac/browsing_data_deletion_unittest.mm b/device/fido/mac/browsing_data_deletion_unittest.mm
index b955d52..2efe18d 100644
--- a/device/fido/mac/browsing_data_deletion_unittest.mm
+++ b/device/fido/mac/browsing_data_deletion_unittest.mm
@@ -13,8 +13,8 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_future.h"
-#include "crypto/apple_keychain_v2.h"
-#include "crypto/fake_apple_keychain_v2.h"
+#include "crypto/apple/fake_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 #include "device/base/features.h"
 #include "device/fido/ctap_make_credential_request.h"
 #include "device/fido/fido_constants.h"
@@ -72,7 +72,7 @@
 // occurred.
 base::apple::ScopedCFTypeRef<CFArrayRef> QueryAllCredentials() {
   base::apple::ScopedCFTypeRef<CFArrayRef> items;
-  OSStatus status = crypto::AppleKeychainV2::GetInstance().ItemCopyMatching(
+  OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemCopyMatching(
       NSToCFPtrCast(BaseQuery()),
       reinterpret_cast<CFTypeRef*>(items.InitializeInto()));
   if (status == errSecItemNotFound) {
@@ -94,7 +94,7 @@
 }
 
 bool ResetKeychain() {
-  OSStatus status = crypto::AppleKeychainV2::GetInstance().ItemDelete(
+  OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemDelete(
       NSToCFPtrCast(BaseQuery()));
   if (status != errSecSuccess && status != errSecItemNotFound) {
     OSSTATUS_DLOG(ERROR, status);
diff --git a/device/fido/mac/credential_store.mm b/device/fido/mac/credential_store.mm
index 739bcc3..6e33ca5c 100644
--- a/device/fido/mac/credential_store.mm
+++ b/device/fido/mac/credential_store.mm
@@ -23,7 +23,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/device_event_log/device_event_log.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 #include "crypto/random.h"
 #include "device/fido/authenticator_data.h"
 #include "device/fido/fido_parsing_utils.h"
@@ -103,7 +103,7 @@
 
   base::apple::ScopedCFTypeRef<CFArrayRef> keychain_items;
   {
-    OSStatus status = crypto::AppleKeychainV2::GetInstance().ItemCopyMatching(
+    OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemCopyMatching(
         NSToCFPtrCast(query),
         reinterpret_cast<CFTypeRef*>(keychain_items.InitializeInto()));
     if (status == errSecItemNotFound) {
@@ -262,14 +262,14 @@
 
   base::apple::ScopedCFTypeRef<CFErrorRef> cferr;
   base::apple::ScopedCFTypeRef<SecKeyRef> private_key =
-      crypto::AppleKeychainV2::GetInstance().KeyCreateRandomKey(
+      crypto::apple::KeychainV2::GetInstance().KeyCreateRandomKey(
           NSToCFPtrCast(params), cferr.InitializeInto());
   if (!private_key) {
     FIDO_LOG(ERROR) << "SecKeyCreateRandomKey failed: " << cferr.get();
     return std::nullopt;
   }
   base::apple::ScopedCFTypeRef<SecKeyRef> public_key(
-      crypto::AppleKeychainV2::GetInstance().KeyCopyPublicKey(
+      crypto::apple::KeychainV2::GetInstance().KeyCopyPublicKey(
           private_key.get()));
   if (!public_key) {
     FIDO_LOG(ERROR) << "SecKeyCopyPublicKey failed";
@@ -338,14 +338,14 @@
 
   base::apple::ScopedCFTypeRef<CFErrorRef> cferr;
   base::apple::ScopedCFTypeRef<SecKeyRef> private_key =
-      crypto::AppleKeychainV2::GetInstance().KeyCreateRandomKey(
+      crypto::apple::KeychainV2::GetInstance().KeyCreateRandomKey(
           NSToCFPtrCast(params), cferr.InitializeInto());
   if (!private_key) {
     FIDO_LOG(ERROR) << "SecKeyCreateRandomKey failed: " << cferr.get();
     return std::nullopt;
   }
   base::apple::ScopedCFTypeRef<SecKeyRef> public_key(
-      crypto::AppleKeychainV2::GetInstance().KeyCopyPublicKey(
+      crypto::apple::KeychainV2::GetInstance().KeyCopyPublicKey(
           private_key.get()));
   if (!public_key) {
     FIDO_LOG(ERROR) << "SecKeyCopyPublicKey failed";
@@ -503,7 +503,7 @@
   query[CFToNSPtrCast(kSecMatchLimit)] = CFToNSPtrCast(kSecMatchLimitAll);
 
   base::apple::ScopedCFTypeRef<CFArrayRef> keychain_items;
-  OSStatus status = crypto::AppleKeychainV2::GetInstance().ItemCopyMatching(
+  OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemCopyMatching(
       NSToCFPtrCast(query),
       reinterpret_cast<CFTypeRef*>(keychain_items.InitializeInto()));
   if (status == errSecItemNotFound) {
@@ -611,7 +611,7 @@
   //     CFToNSPtrCast(kSecValueRef) : (__bridge id)sec_key_ref,
   //   };
   //   OSStatus status =
-  //       AppleKeychainV2::GetInstance().ItemDelete(NSToCFPtrCast(query));
+  //       KeychainV2::GetInstance().ItemDelete(NSToCFPtrCast(query));
   //
   // But on macOS that looks for `sec_key_ref` in the legacy keychain instead of
   // the "iOS" keychain that secure enclave credentials live in, and so the call
@@ -630,7 +630,7 @@
   };
 
   OSStatus status =
-      crypto::AppleKeychainV2::GetInstance().ItemDelete(NSToCFPtrCast(query));
+      crypto::apple::KeychainV2::GetInstance().ItemDelete(NSToCFPtrCast(query));
   if (status != errSecSuccess) {
     OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed";
     return false;
@@ -676,7 +676,7 @@
   };
   NSDictionary* params =
       @{CFToNSPtrCast(kSecAttrApplicationTag) : sealed_metadata_data};
-  OSStatus status = crypto::AppleKeychainV2::GetInstance().ItemUpdate(
+  OSStatus status = crypto::apple::KeychainV2::GetInstance().ItemUpdate(
       NSToCFPtrCast(query), NSToCFPtrCast(params));
   if (status != errSecSuccess) {
     OSSTATUS_DLOG(ERROR, status) << "SecItemUpdate failed";
diff --git a/device/fido/mac/credential_store_unittest.mm b/device/fido/mac/credential_store_unittest.mm
index a36ff001..7a68ba3 100644
--- a/device/fido/mac/credential_store_unittest.mm
+++ b/device/fido/mac/credential_store_unittest.mm
@@ -11,7 +11,7 @@
 
 #include "base/apple/foundation_util.h"
 #include "base/mac/mac_util.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/mac/authenticator_config.h"
 #include "device/fido/mac/credential_store.h"
 #include "device/fido/public_key_credential_user_entity.h"
@@ -72,7 +72,7 @@
   AuthenticatorConfig config_{
       .keychain_access_group = "test-keychain-access-group",
       .metadata_secret = "TestMetadataSecret"};
-  crypto::ScopedFakeAppleKeychainV2 keychain_{config_.keychain_access_group};
+  crypto::apple::ScopedFakeKeychainV2 keychain_{config_.keychain_access_group};
   TouchIdCredentialStore store_{config_};
 };
 
diff --git a/device/fido/mac/scoped_touch_id_test_environment.h b/device/fido/mac/scoped_touch_id_test_environment.h
index f53295a..9756baf 100644
--- a/device/fido/mac/scoped_touch_id_test_environment.h
+++ b/device/fido/mac/scoped_touch_id_test_environment.h
@@ -10,9 +10,9 @@
 #include "base/component_export.h"
 #include "device/fido/mac/authenticator_config.h"
 
-namespace crypto {
-class ScopedFakeAppleKeychainV2;
-}  // namespace crypto
+namespace crypto::apple {
+class ScopedFakeKeychainV2;
+}  // namespace crypto::apple
 
 namespace device::fido::mac {
 
@@ -52,7 +52,7 @@
   // Will prevent the next call to PromptTouchId from running the callback.
   void DoNotResolveNextPrompt();
 
-  crypto::ScopedFakeAppleKeychainV2* keychain() { return keychain_.get(); }
+  crypto::apple::ScopedFakeKeychainV2* keychain() { return keychain_.get(); }
 
  private:
   static std::unique_ptr<TouchIdContext> ForwardCreate();
@@ -67,7 +67,7 @@
   TouchIdAvailableFuncPtr touch_id_context_touch_id_available_ptr_;
 
   AuthenticatorConfig config_;
-  std::unique_ptr<crypto::ScopedFakeAppleKeychainV2> keychain_;
+  std::unique_ptr<crypto::apple::ScopedFakeKeychainV2> keychain_;
   std::unique_ptr<FakeTouchIdContext> next_touch_id_context_;
   bool touch_id_available_ = true;
 };
diff --git a/device/fido/mac/scoped_touch_id_test_environment.mm b/device/fido/mac/scoped_touch_id_test_environment.mm
index 086b58acd..baf9b5f6 100644
--- a/device/fido/mac/scoped_touch_id_test_environment.mm
+++ b/device/fido/mac/scoped_touch_id_test_environment.mm
@@ -10,7 +10,7 @@
 
 #include "base/check.h"
 #include "base/memory/ptr_util.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "device/fido/mac/authenticator_config.h"
 #include "device/fido/mac/fake_touch_id_context.h"
 
@@ -21,7 +21,7 @@
 ScopedTouchIdTestEnvironment::ScopedTouchIdTestEnvironment(
     AuthenticatorConfig config)
     : config_(std::move(config)),
-      keychain_(std::make_unique<crypto::ScopedFakeAppleKeychainV2>(
+      keychain_(std::make_unique<crypto::apple::ScopedFakeKeychainV2>(
           config_.keychain_access_group)) {
   DCHECK(!g_current_environment);
   g_current_environment = this;
diff --git a/device/fido/mac/touch_id_context.mm b/device/fido/mac/touch_id_context.mm
index 31814839..5e10031 100644
--- a/device/fido/mac/touch_id_context.mm
+++ b/device/fido/mac/touch_id_context.mm
@@ -20,8 +20,8 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "components/device_event_log/device_event_log.h"
-#include "crypto/apple_keychain_util.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_util.h"
+#include "crypto/apple/keychain_v2.h"
 #include "device/fido/mac/authenticator_config.h"
 
 using base::apple::CFToNSPtrCast;
@@ -48,7 +48,7 @@
 
   base::apple::ScopedCFTypeRef<CFErrorRef> cferr;
   base::apple::ScopedCFTypeRef<SecKeyRef> private_key(
-      crypto::AppleKeychainV2::GetInstance().KeyCreateRandomKey(
+      crypto::apple::KeychainV2::GetInstance().KeyCreateRandomKey(
           NSToCFPtrCast(params), cferr.InitializeInto()));
   return !!private_key;
 }
@@ -84,7 +84,7 @@
   // entitlement that is configured by the embedder; that user authentication
   // with biometry, watch, or device passcode possible; and that the device has
   // a secure enclave.
-  if (!crypto::ExecutableHasKeychainAccessGroupEntitlement(
+  if (!crypto::apple::ExecutableHasKeychainAccessGroupEntitlement(
           config.keychain_access_group)) {
     FIDO_LOG(ERROR)
         << "Touch ID authenticator unavailable because keychain-access-group "
diff --git a/device/fido/mac/util.mm b/device/fido/mac/util.mm
index 7bd2b04..6b87adba 100644
--- a/device/fido/mac/util.mm
+++ b/device/fido/mac/util.mm
@@ -20,7 +20,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "build/branding_buildflags.h"
 #include "components/cbor/writer.h"
-#include "crypto/apple_keychain_v2.h"
+#include "crypto/apple/keychain_v2.h"
 #include "crypto/hash.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/p256_public_key.h"
@@ -126,7 +126,7 @@
                     client_data_hash.size());
   ScopedCFTypeRef<CFErrorRef> err;
   ScopedCFTypeRef<CFDataRef> sig_data(
-      crypto::AppleKeychainV2::GetInstance().KeyCreateSignature(
+      crypto::apple::KeychainV2::GetInstance().KeyCreateSignature(
           private_key, kSecKeyAlgorithmECDSASignatureMessageX962SHA256,
           sig_input.get(), err.InitializeInto()));
   if (!sig_data) {
@@ -225,7 +225,7 @@
     return *flag;
   }
 
-  return crypto::AppleKeychainV2::GetInstance().LAContextCanEvaluatePolicy(
+  return crypto::apple::KeychainV2::GetInstance().LAContextCanEvaluatePolicy(
       LAPolicyDeviceOwnerAuthenticationWithBiometrics, /*error=*/nil);
 }
 
diff --git a/docs/mojo_ipc_conversion.md b/docs/mojo_ipc_conversion.md
index 28a8438..7b02298 100644
--- a/docs/mojo_ipc_conversion.md
+++ b/docs/mojo_ipc_conversion.md
@@ -390,7 +390,7 @@
 namespace blink {
 
 class Example {
-  virtual void SendArray(const WTF::String& param1, const WTF::Vector<int32_t>& param2) = 0;
+  virtual void SendArray(const ::blink::String& param1, const ::blink::Vector<int32_t>& param2) = 0;
 }
 
 } // namespace blink
@@ -409,8 +409,8 @@
 ### Binding callbacks
 
 Mojo methods that return a value take an instance of `base::OnceCallback`.
-Use `WTF::BindOnce()` and an appropriate wrapper function depending on the type of
-object and the callback.
+Use `blink::BindOnce()` and an appropriate wrapper function depending on the
+type of object and the callback.
 
 For garbage-collected (Oilpan) classes owning the `mojo::Remote`, it is recommended
 to use `WrapWeakPersistent(this)` for connection error handlers since they
@@ -422,11 +422,11 @@
 
 ``` cpp
 // src/third_party/blink/renderer/modules/device_orientation/device_sensor_entry.cc
-sensor_.set_connection_error_handler(WTF::BindOnce(
+sensor_.set_connection_error_handler(blink::BindOnce(
     &DeviceSensorEntry::HandleSensorError, WrapWeakPersistent(this)));
 sensor_->ConfigureReadingChangeNotifications(/*enabled=*/false);
 sensor_->AddConfiguration(
-    std::move(config), WTF::BindOnce(&DeviceSensorEntry::OnSensorAddConfiguration,
+    std::move(config), blink::BindOnce(&DeviceSensorEntry::OnSensorAddConfiguration,
                                  WrapWeakPersistent(this)));
 ```
 
@@ -436,17 +436,17 @@
 ``` cpp
 // src/third_party/blink/renderer/modules/nfc/nfc.cc
 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
-... 
-nfc_->CancelAllWatches(WTF::BindOnce(&NFC::OnRequestCompleted,
+...
+nfc_->CancelAllWatches(blink::BindOnce(&NFC::OnRequestCompleted,
                                  WrapPersistent(this),
                                  WrapPersistent(resolver)));
 ```
 
-Non-garbage-collected objects can use `WTF::Unretained(this)` for both response
-and error handler callbacks when the `mojo::Remote` is owned by the object bound
-to the callback or the object is guaranteed to outlive the Mojo connection for
-another reason. Otherwise a weak pointer should be used. However, it is not a
-common pattern since using Oilpan is recommended for all Blink code.
+Non-garbage-collected objects can use `blink::Unretained(this)` for both
+response and error handler callbacks when the `mojo::Remote` is owned by the
+object bound to the callback or the object is guaranteed to outlive the Mojo
+connection for another reason. Otherwise a weak pointer should be used. However,
+it is not a common pattern since using Oilpan is recommended for all Blink code.
 
 ### Implementing Mojo interfaces in Blink
 
diff --git a/docs/privacy_budget/privacy_budget_code_locations.md b/docs/privacy_budget/privacy_budget_code_locations.md
index ae61dd1b..5f60d68f 100644
--- a/docs/privacy_budget/privacy_budget_code_locations.md
+++ b/docs/privacy_budget/privacy_budget_code_locations.md
@@ -45,7 +45,7 @@
 * [`third_party/blink/renderer/platform/privacy_budget`](../../third_party/blink/renderer/platform/privacy_budget)
 
 Functions for constructing [`blink::IdentifiableToken`] values from
-`platform/wtf` types. E.g. `WTF::String`.
+`platform/wtf` types. E.g. `blink::String`.
 
 See the [`DEPS`][platform/pb/deps] in that directory for the paths that this
 component can depend on. In particular:
diff --git a/docs/privacy_budget/privacy_budget_instrumentation.md b/docs/privacy_budget/privacy_budget_instrumentation.md
index 46114883..21563ee 100644
--- a/docs/privacy_budget/privacy_budget_instrumentation.md
+++ b/docs/privacy_budget/privacy_budget_instrumentation.md
@@ -135,13 +135,13 @@
    going to be sensitive). Then only extract a maximum of 16 bits from the
    string.
 
-   For `blink::String` a.k.a. `WTF::String` types, this is implemented as
+   For `blink::String` type, this is implemented as
    `IdentifiabilitySensitiveStringToken()` and
    `IdentifiabilitySensitiveCaseFoldingStringToken()` in
    [`identifiability_digest_helpers.h`].
    ***
 
-   * If you are about to construct a token out of a `WTF::String` type use
+   * If you are about to construct a token out of a `blink::String` type use
      one of the helpers in [`identifiability_digest_helpers.h`]. As mentioned
      above, you'll need to decide:
 
diff --git a/docs/security/document-domain.md b/docs/security/document-domain.md
index 2046870..5e2bbad 100644
--- a/docs/security/document-domain.md
+++ b/docs/security/document-domain.md
@@ -91,10 +91,6 @@
 
 How to enable/disable the deprecation:
 
-### Enable the Warning (Before M100)
-
-* Start Chrome with `--enable-features=OriginAgentClusterDefaultWarning`
-
 ### Enable the Deprecation (Scheduled for M106)
 
 * In [chrome://flags](chrome://flags#origin-agent-cluster-default), go to
diff --git a/extensions/renderer/resource_bundle_source_map.cc b/extensions/renderer/resource_bundle_source_map.cc
index 3ad8553..881588d9 100644
--- a/extensions/renderer/resource_bundle_source_map.cc
+++ b/extensions/renderer/resource_bundle_source_map.cc
@@ -47,7 +47,7 @@
 ResourceBundleSourceMap::~ResourceBundleSourceMap() {
 }
 
-void ResourceBundleSourceMap::RegisterSource(const char* const name,
+void ResourceBundleSourceMap::RegisterSource(std::string_view name,
                                              int resource_id) {
   base::AutoLock lock(lock_);
   resource_map_.emplace(name, resource_id);
diff --git a/extensions/renderer/resource_bundle_source_map.h b/extensions/renderer/resource_bundle_source_map.h
index ffc5bfa..e642d4a 100644
--- a/extensions/renderer/resource_bundle_source_map.h
+++ b/extensions/renderer/resource_bundle_source_map.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/memory/raw_ptr.h"
 #include "base/synchronization/lock.h"
@@ -34,7 +35,9 @@
                                   const std::string& name) const override;
   bool Contains(const std::string& name) const override;
 
-  void RegisterSource(const char* const name, int resource_id);
+  // `name` must outlive `this`. Preferably, the name string has static storage
+  // duration.
+  void RegisterSource(std::string_view name, int resource_id);
 
  private:
   struct ResourceInfo {
@@ -53,7 +56,7 @@
   raw_ptr<const ui::ResourceBundle, DanglingUntriaged> resource_bundle_;
 
   mutable base::Lock lock_;
-  std::map<std::string, ResourceInfo> resource_map_ GUARDED_BY(lock_);
+  std::map<std::string_view, ResourceInfo> resource_map_ GUARDED_BY(lock_);
 };
 
 }  // namespace extensions
diff --git a/fuchsia_web/runners/cast/cast_runner.cml b/fuchsia_web/runners/cast/cast_runner.cml
index 5fc2733..4075c9c 100644
--- a/fuchsia_web/runners/cast/cast_runner.cml
+++ b/fuchsia_web/runners/cast/cast_runner.cml
@@ -18,6 +18,8 @@
     // Enable graceful teardown since the web_instance uses dynamic
     // capabilities via this Component.
     lifecycle: { stop_event: "notify" },
+    // Raise an exception if the runner tries to use a bad handle.
+    deny_bad_handles: "true",
   },
   capabilities: [
     {
diff --git a/fuchsia_web/webengine/web_instance-common.shard.cml b/fuchsia_web/webengine/web_instance-common.shard.cml
index da271b3..a531d9d4 100644
--- a/fuchsia_web/webengine/web_instance-common.shard.cml
+++ b/fuchsia_web/webengine/web_instance-common.shard.cml
@@ -5,6 +5,9 @@
   program: {
     runner: "elf",
     binary: "web_engine_exe",
+
+    // Raise an exception if the browser tries to use a bad handle.
+    deny_bad_handles: "true",
   },
   capabilities: [
     {
diff --git a/gin/per_context_data.cc b/gin/per_context_data.cc
index 5a10017..0dbfbc6 100644
--- a/gin/per_context_data.cc
+++ b/gin/per_context_data.cc
@@ -18,7 +18,7 @@
 
 PerContextData::PerContextData(ContextHolder* context_holder,
                                v8::Local<v8::Context> context)
-    : context_holder_(context_holder), runner_(nullptr) {
+    : context_holder_(context_holder) {
   context->SetAlignedPointerInEmbedderData(kGinPerContextDataIndex, this);
 }
 
diff --git a/gin/per_context_data.h b/gin/per_context_data.h
index 6c6b8dcd..4bb773a 100644
--- a/gin/per_context_data.h
+++ b/gin/per_context_data.h
@@ -13,7 +13,6 @@
 namespace gin {
 
 class ContextHolder;
-class Runner;
 
 // There is one instance of PerContextData per v8::Context managed by Gin. This
 // class stores all the Gin-related data that varies per context. Arbitrary data
@@ -31,16 +30,10 @@
   // Can return NULL after the ContextHolder has detached from context.
   static PerContextData* From(v8::Local<v8::Context> context);
 
-  // The Runner associated with this context. To execute script in this context,
-  // please use the appropriate API on Runner.
-  Runner* runner() const { return runner_; }
-  void set_runner(Runner* runner) { runner_ = runner; }
-
   ContextHolder* context_holder() { return context_holder_; }
 
  private:
   raw_ptr<ContextHolder, DanglingUntriaged> context_holder_;
-  raw_ptr<Runner> runner_;
 };
 
 }  // namespace gin
diff --git a/gin/shell_runner.cc b/gin/shell_runner.cc
index 4805498..93aad1e 100644
--- a/gin/shell_runner.cc
+++ b/gin/shell_runner.cc
@@ -48,7 +48,6 @@
 
   context_holder_ = std::make_unique<ContextHolder>(isolate);
   context_holder_->SetContext(context);
-  PerContextData::From(context)->set_runner(this);
 
   v8::Context::Scope scope(context);
   delegate_->DidCreateContext(this);
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 869304b..a04dc73 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -135,6 +135,10 @@
     ]
   }
   deps += [ "//third_party/angle:translator" ]
+
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
 
 if (!is_android && !is_fuchsia && !is_chromeos && !is_ios) {
@@ -380,6 +384,10 @@
   if (is_chromeos) {
     deps += [ "//ui/gfx/linux:gbm" ]
   }
+
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
 
 test("gpu_unittests") {
@@ -676,6 +684,10 @@
   if (is_apple) {
     deps += [ "//ui/accelerated_widget_mac:accelerated_widget_mac" ]
   }
+
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
 
 test("gpu_perftests") {
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index f1ecb293..187dec6 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -21,6 +21,10 @@
 #include "gpu/config/gpu_util.h"
 #include "third_party/re2/src/re2/re2.h"
 
+#if BUILDFLAG(IS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace gpu {
 namespace {
 
@@ -706,8 +710,17 @@
   if (os == kOsAny)
     os = GetOsType();
   std::string processed_os_version = os_version;
-  if (processed_os_version.empty())
+  if (processed_os_version.empty()) {
+#if BUILDFLAG(IS_WIN)
+    base::win::OSInfo::VersionNumber version_number =
+        base::win::OSInfo::GetInstance()->version_number();
+    processed_os_version = base::StringPrintf(
+        "%d.%d.%d.%d", version_number.major, version_number.minor,
+        version_number.build, version_number.patch);
+#else
     processed_os_version = base::SysInfo::OperatingSystemVersion();
+#endif
+  }
   // Get rid of the non numbers because later processing expects a valid
   // version string in the format of "a.b.c".
   size_t pos = processed_os_version.find_first_not_of("0123456789.");
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 77b69bc..71858019 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -184,4 +184,8 @@
     "//gpu/ipc/common",
     "//ui/gl:test_support",
   ]
+
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
diff --git a/gpu/vulkan/BUILD.gn b/gpu/vulkan/BUILD.gn
index 73e077ecb..0ff2f57 100644
--- a/gpu/vulkan/BUILD.gn
+++ b/gpu/vulkan/BUILD.gn
@@ -228,6 +228,10 @@
       sources += [ "tests/native_window_android.cc" ]
       deps += [ "//ui/gl" ]
     }
+
+    # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+    # enable the diagnostic by removing this line.
+    configs += [ "//build/config/compiler:no_exit_time_destructors" ]
   }
 
   # TODO(penghuang): support more platforms
@@ -274,6 +278,10 @@
 
         deps += [ "//ui/ozone" ]
       }
+
+      # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+      # enable the diagnostic by removing this line.
+      configs += [ "//build/config/compiler:no_exit_time_destructors" ]
     }
   }
 }
diff --git a/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt b/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt
index 27e2330..eb48ceb 100644
--- a/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt
+++ b/infra/config/generated/builder-owners/chrome-sanitizer-builder-owners@google.com.txt
@@ -16,6 +16,7 @@
 ci/Linux UBSan Tests
 ci/MSAN Release (chained origins)
 ci/MSAN Release (no origins)
+ci/Mac ARM64 ASAN Release
 ci/Mac ASAN Release
 ci/Mac ASan 64 Builder
 ci/Mac ASan 64 Tests (1)
@@ -34,4 +35,5 @@
 try/linux-blink-asan-rel
 try/linux-blink-leak-rel
 try/linux-blink-msan-rel
-try/linux_chromium_ubsan_rel_ng
\ No newline at end of file
+try/linux_chromium_ubsan_rel_ng
+try/mac-arm64-asan-rel
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/gn-args.json b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/gn-args.json
new file mode 100644
index 0000000..a42bd352
--- /dev/null
+++ b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/gn-args.json
@@ -0,0 +1,15 @@
+{
+  "gn_args": {
+    "dcheck_always_on": false,
+    "enable_ipc_fuzzer": true,
+    "is_asan": true,
+    "is_component_build": false,
+    "is_debug": false,
+    "target_cpu": "arm64",
+    "target_os": "mac",
+    "use_reclient": false,
+    "use_remoteexec": true,
+    "use_siso": true,
+    "v8_enable_verify_heap": true
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/properties.json b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/properties.json
new file mode 100644
index 0000000..afeadc9
--- /dev/null
+++ b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/properties.json
@@ -0,0 +1,80 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "additional_exclusions": [
+        "infra/config/generated/builders/ci/Mac ARM64 ASAN Release/gn-args.json"
+      ],
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Mac ARM64 ASAN Release",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "builder_group": "chromium.fuzz",
+              "clusterfuzz_archive": {
+                "archive_name_prefix": "asan",
+                "archive_subdir": "arm64",
+                "gs_acl": "public-read",
+                "gs_bucket": "chromium-browser-asan"
+              },
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "clobber",
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_asan",
+                "target_arch": "arm",
+                "target_bits": 64,
+                "target_platform": "mac"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Mac ARM64 ASAN Release",
+          "project": "chromium"
+        }
+      ],
+      "mirroring_builder_group_and_names": [
+        {
+          "builder": "mac-arm64-asan-rel",
+          "group": "tryserver.chromium.fuzz"
+        }
+      ],
+      "retry_failed_shards": true,
+      "targets_spec_directory": "src/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/targets"
+    }
+  },
+  "$build/siso": {
+    "configs": [
+      "builder"
+    ],
+    "enable_cloud_monitoring": true,
+    "enable_cloud_profiler": true,
+    "enable_cloud_trace": true,
+    "experiments": [],
+    "metrics_project": "chromium-reclient-metrics",
+    "project": "rbe-chromium-trusted",
+    "remote_jobs": 250
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "chromium.fuzz",
+  "recipe": "chromium"
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/shadow-properties.json b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/shadow-properties.json
new file mode 100644
index 0000000..78dedff8
--- /dev/null
+++ b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/shadow-properties.json
@@ -0,0 +1,14 @@
+{
+  "$build/siso": {
+    "configs": [
+      "builder"
+    ],
+    "enable_cloud_monitoring": true,
+    "enable_cloud_profiler": true,
+    "enable_cloud_trace": true,
+    "experiments": [],
+    "metrics_project": "chromium-reclient-metrics",
+    "project": "rbe-chromium-untrusted",
+    "remote_jobs": 250
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/targets/chromium.fuzz.json b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/targets/chromium.fuzz.json
new file mode 100644
index 0000000..4de8fb8
--- /dev/null
+++ b/infra/config/generated/builders/ci/Mac ARM64 ASAN Release/targets/chromium.fuzz.json
@@ -0,0 +1,7 @@
+{
+  "Mac ARM64 ASAN Release": {
+    "additional_compile_targets": [
+      "chromium_builder_asan"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/ios-blink-rel-fyi/properties.json b/infra/config/generated/builders/ci/ios-blink-rel-fyi/properties.json
index 1fcd2ad..1ab1a5d 100644
--- a/infra/config/generated/builders/ci/ios-blink-rel-fyi/properties.json
+++ b/infra/config/generated/builders/ci/ios-blink-rel-fyi/properties.json
@@ -71,5 +71,5 @@
   },
   "builder_group": "chromium.fyi",
   "recipe": "chromium",
-  "xcode_build_version": "17a5276g"
+  "xcode_build_version": "17a5285i"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/ios-blink-rel-fyi/targets/chromium.fyi.json b/infra/config/generated/builders/ci/ios-blink-rel-fyi/targets/chromium.fyi.json
index a095063a..da7e5d0b 100644
--- a/infra/config/generated/builders/ci/ios-blink-rel-fyi/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/ci/ios-blink-rel-fyi/targets/chromium.fyi.json
@@ -13,7 +13,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -42,7 +42,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -61,7 +61,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -90,7 +90,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -112,7 +112,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -141,7 +141,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -160,7 +160,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -189,7 +189,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -208,7 +208,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -237,7 +237,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -256,7 +256,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -285,7 +285,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -307,7 +307,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -341,7 +341,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -360,7 +360,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -389,7 +389,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -408,7 +408,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -437,7 +437,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -456,7 +456,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -485,7 +485,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -504,7 +504,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -533,7 +533,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -555,7 +555,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -584,7 +584,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -605,7 +605,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -634,7 +634,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -655,7 +655,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -684,7 +684,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -705,7 +705,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -734,7 +734,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -755,7 +755,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -784,7 +784,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -806,7 +806,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -835,7 +835,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -854,7 +854,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -883,7 +883,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -902,7 +902,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -931,7 +931,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -950,7 +950,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -979,7 +979,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -998,7 +998,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1027,7 +1027,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1046,7 +1046,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1075,7 +1075,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1094,7 +1094,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1123,7 +1123,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1142,7 +1142,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1171,7 +1171,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1192,7 +1192,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1221,7 +1221,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1240,7 +1240,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1269,7 +1269,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1288,7 +1288,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1317,7 +1317,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1336,7 +1336,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1365,7 +1365,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1386,7 +1386,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1415,7 +1415,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1434,7 +1434,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1463,7 +1463,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1482,7 +1482,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1511,7 +1511,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1530,7 +1530,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1559,7 +1559,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1578,7 +1578,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1607,7 +1607,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1626,7 +1626,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1655,7 +1655,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1676,7 +1676,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1705,7 +1705,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1730,7 +1730,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1759,7 +1759,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1784,7 +1784,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1813,7 +1813,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1832,7 +1832,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1861,7 +1861,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1882,7 +1882,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1911,7 +1911,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1930,7 +1930,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1959,7 +1959,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1978,7 +1978,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2007,7 +2007,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2026,7 +2026,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2055,7 +2055,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2074,7 +2074,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2103,7 +2103,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2122,7 +2122,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2151,7 +2151,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2171,7 +2171,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2200,7 +2200,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2219,7 +2219,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2248,7 +2248,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2267,7 +2267,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2296,7 +2296,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2315,7 +2315,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2344,7 +2344,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2363,7 +2363,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2392,7 +2392,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2412,7 +2412,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2441,7 +2441,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2460,7 +2460,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2489,7 +2489,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2508,7 +2508,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2537,7 +2537,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2556,7 +2556,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2585,7 +2585,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2607,7 +2607,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2636,7 +2636,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2655,7 +2655,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2684,7 +2684,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2703,7 +2703,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2732,7 +2732,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/ci/ios18-sdk-simulator/properties.json b/infra/config/generated/builders/ci/ios18-sdk-simulator/properties.json
index a75fbea..aae814e 100644
--- a/infra/config/generated/builders/ci/ios18-sdk-simulator/properties.json
+++ b/infra/config/generated/builders/ci/ios18-sdk-simulator/properties.json
@@ -70,5 +70,5 @@
   },
   "builder_group": "chromium.fyi",
   "recipe": "chromium",
-  "xcode_build_version": "17a5276g"
+  "xcode_build_version": "17a5285i"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/ios18-sdk-simulator/targets/chromium.fyi.json b/infra/config/generated/builders/ci/ios18-sdk-simulator/targets/chromium.fyi.json
index c59bc20..5e870a3 100644
--- a/infra/config/generated/builders/ci/ios18-sdk-simulator/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/ci/ios18-sdk-simulator/targets/chromium.fyi.json
@@ -13,7 +13,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -42,7 +42,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -61,7 +61,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -90,7 +90,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -109,7 +109,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -138,7 +138,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -157,7 +157,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -186,7 +186,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -205,7 +205,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -234,7 +234,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -253,7 +253,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -282,7 +282,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -301,7 +301,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -330,7 +330,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -349,7 +349,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -378,7 +378,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -397,7 +397,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -426,7 +426,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -445,7 +445,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -474,7 +474,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -493,7 +493,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -522,7 +522,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -541,7 +541,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -570,7 +570,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -589,7 +589,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -618,7 +618,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -637,7 +637,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -666,7 +666,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -685,7 +685,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -714,7 +714,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -733,7 +733,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -762,7 +762,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -781,7 +781,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -810,7 +810,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -829,7 +829,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -858,7 +858,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -877,7 +877,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -906,7 +906,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -925,7 +925,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -954,7 +954,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -973,7 +973,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1002,7 +1002,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1024,7 +1024,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1053,7 +1053,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1076,7 +1076,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1105,7 +1105,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1128,7 +1128,111 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_signin_eg2tests_module iPad Air (5th generation) 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "ios_chrome_signin_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
+        "variant_id": "iPad Air (5th generation) 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPhone 14",
+          "--version",
+          "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_signin_eg2tests_module iPhone 14 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "ios_chrome_signin_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
+        "variant_id": "iPhone 14 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPad Air (5th generation)",
+          "--version",
+          "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1157,7 +1261,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1179,7 +1283,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1208,7 +1312,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1227,7 +1331,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1256,7 +1360,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1275,7 +1379,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1304,7 +1408,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1323,7 +1427,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1352,7 +1456,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1368,10 +1472,114 @@
           "iPad Air (5th generation)",
           "--version",
           "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_web_eg2tests_module iPad Air (5th generation) 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "ios_chrome_web_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
+        "variant_id": "iPad Air (5th generation) 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPhone 14",
+          "--version",
+          "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_web_eg2tests_module iPhone 14 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "ios_chrome_web_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
+        "variant_id": "iPhone 14 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPad Air (5th generation)",
+          "--version",
+          "26.0",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1400,7 +1608,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1419,7 +1627,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1448,7 +1656,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1468,7 +1676,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1497,7 +1705,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1517,7 +1725,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1546,7 +1754,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1565,7 +1773,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1594,7 +1802,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1614,7 +1822,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1643,7 +1851,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1663,7 +1871,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1692,7 +1900,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1711,7 +1919,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1740,7 +1948,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1759,7 +1967,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1788,7 +1996,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1807,7 +2015,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1836,7 +2044,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1855,7 +2063,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1884,7 +2092,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1903,7 +2111,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1932,7 +2140,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1951,7 +2159,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1980,7 +2188,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1999,7 +2207,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2028,7 +2236,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2047,7 +2255,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2076,7 +2284,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2095,7 +2303,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2124,7 +2332,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2143,7 +2351,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2172,7 +2380,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2191,7 +2399,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2220,7 +2428,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2239,7 +2447,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2268,7 +2476,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2287,7 +2495,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2316,7 +2524,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2335,7 +2543,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2364,7 +2572,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2383,7 +2591,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2412,7 +2620,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2431,7 +2639,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2460,7 +2668,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2479,7 +2687,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2508,7 +2716,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2527,7 +2735,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2556,7 +2764,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2575,7 +2783,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2604,7 +2812,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2623,7 +2831,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2652,7 +2860,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2671,7 +2879,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2700,7 +2908,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/ci/ios26-beta-simulator/targets/chromium.fyi.json b/infra/config/generated/builders/ci/ios26-beta-simulator/targets/chromium.fyi.json
index 6179de37..bca42ac 100644
--- a/infra/config/generated/builders/ci/ios26-beta-simulator/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/ci/ios26-beta-simulator/targets/chromium.fyi.json
@@ -13,7 +13,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -42,7 +42,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -61,7 +61,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -90,7 +90,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -109,7 +109,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -138,7 +138,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -157,7 +157,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -186,7 +186,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -205,7 +205,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -234,7 +234,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -253,7 +253,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -282,7 +282,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -301,7 +301,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -330,7 +330,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -349,7 +349,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -378,7 +378,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -397,7 +397,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -426,7 +426,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -445,7 +445,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -474,7 +474,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -493,7 +493,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -522,7 +522,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -541,7 +541,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -570,7 +570,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -589,7 +589,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -618,7 +618,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -637,7 +637,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -666,7 +666,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -685,7 +685,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -714,7 +714,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -733,7 +733,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -762,7 +762,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -781,7 +781,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -810,7 +810,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -829,7 +829,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -858,7 +858,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -877,7 +877,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -906,7 +906,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -925,7 +925,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -954,7 +954,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -973,7 +973,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1002,7 +1002,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1024,7 +1024,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1053,7 +1053,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1076,7 +1076,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1105,7 +1105,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1130,7 +1130,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1159,7 +1159,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1184,7 +1184,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1213,7 +1213,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1238,7 +1238,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1267,7 +1267,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1292,7 +1292,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1321,7 +1321,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1344,7 +1344,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1373,7 +1373,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1396,7 +1396,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1425,7 +1425,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1448,7 +1448,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1477,7 +1477,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1499,7 +1499,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1528,7 +1528,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1552,7 +1552,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1581,7 +1581,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1606,7 +1606,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1635,7 +1635,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1655,7 +1655,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1684,7 +1684,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1703,7 +1703,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1732,7 +1732,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1751,7 +1751,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1780,7 +1780,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1802,7 +1802,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1831,7 +1831,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1854,7 +1854,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1883,7 +1883,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1903,7 +1903,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1932,7 +1932,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1951,7 +1951,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1980,7 +1980,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2000,7 +2000,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2029,7 +2029,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2049,7 +2049,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2078,7 +2078,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2097,7 +2097,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2126,7 +2126,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2146,7 +2146,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2175,7 +2175,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2195,7 +2195,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2224,7 +2224,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2243,7 +2243,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2272,7 +2272,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2291,7 +2291,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2320,7 +2320,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2339,7 +2339,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2368,7 +2368,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2387,7 +2387,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2416,7 +2416,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2438,7 +2438,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2467,7 +2467,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2489,7 +2489,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2518,7 +2518,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2537,7 +2537,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2566,7 +2566,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2585,7 +2585,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2614,7 +2614,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2633,7 +2633,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2662,7 +2662,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2681,7 +2681,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2710,7 +2710,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2729,7 +2729,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2758,7 +2758,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2777,7 +2777,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2806,7 +2806,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2825,7 +2825,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2854,7 +2854,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2873,7 +2873,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2902,7 +2902,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2921,7 +2921,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2950,7 +2950,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2969,7 +2969,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2998,7 +2998,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3017,7 +3017,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3046,7 +3046,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3065,7 +3065,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3094,7 +3094,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3113,7 +3113,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3142,7 +3142,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3161,7 +3161,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3190,7 +3190,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3209,7 +3209,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3238,7 +3238,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3257,7 +3257,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3286,7 +3286,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3305,7 +3305,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3334,7 +3334,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3353,7 +3353,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3382,7 +3382,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3401,7 +3401,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3430,7 +3430,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3449,7 +3449,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3478,7 +3478,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3497,7 +3497,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3526,7 +3526,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3545,7 +3545,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3574,7 +3574,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3593,7 +3593,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3622,7 +3622,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/ci/ios26-sdk-simulator/properties.json b/infra/config/generated/builders/ci/ios26-sdk-simulator/properties.json
index 623cdc94..a8d84f7 100644
--- a/infra/config/generated/builders/ci/ios26-sdk-simulator/properties.json
+++ b/infra/config/generated/builders/ci/ios26-sdk-simulator/properties.json
@@ -70,5 +70,5 @@
   },
   "builder_group": "chromium.fyi",
   "recipe": "chromium",
-  "xcode_build_version": "17a5276g"
+  "xcode_build_version": "17a5285i"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/ios26-sdk-simulator/targets/chromium.fyi.json b/infra/config/generated/builders/ci/ios26-sdk-simulator/targets/chromium.fyi.json
index ba0f4af..9843a5f5 100644
--- a/infra/config/generated/builders/ci/ios26-sdk-simulator/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/ci/ios26-sdk-simulator/targets/chromium.fyi.json
@@ -16,7 +16,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -45,7 +45,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -68,7 +68,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -97,7 +97,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -120,7 +120,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -149,7 +149,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -172,7 +172,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -201,7 +201,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -214,106 +214,6 @@
       },
       {
         "args": [
-          "--platform",
-          "iPad Air (5th generation)",
-          "--version",
-          "26.0",
-          "--xcodebuild-sim-runner",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_signin_eg2tests_module iPad Air (5th generation) 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "ios_chrome_signin_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPad Air (5th generation) 26.0"
-      },
-      {
-        "args": [
-          "--platform",
-          "iPhone 14",
-          "--version",
-          "26.0",
-          "--xcodebuild-sim-runner",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 14 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "ios_chrome_signin_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 14 26.0"
-      },
-      {
-        "args": [
           "--clones",
           "2",
           "--platform",
@@ -324,7 +224,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -353,7 +253,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -376,7 +276,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -405,7 +305,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -422,110 +322,10 @@
           "iPad Air (5th generation)",
           "--version",
           "26.0",
-          "--xcodebuild-sim-runner",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_web_eg2tests_module iPad Air (5th generation) 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "ios_chrome_web_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPad Air (5th generation) 26.0"
-      },
-      {
-        "args": [
-          "--platform",
-          "iPhone 14",
-          "--version",
-          "26.0",
-          "--xcodebuild-sim-runner",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_web_eg2tests_module iPhone 14 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "ios_chrome_web_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone 14 26.0"
-      },
-      {
-        "args": [
-          "--platform",
-          "iPad Air (5th generation)",
-          "--version",
-          "26.0",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -554,7 +354,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -573,7 +373,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -602,7 +402,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -621,7 +421,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -650,7 +450,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -670,7 +470,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -699,7 +499,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -719,7 +519,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -748,7 +548,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -767,7 +567,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -796,7 +596,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -815,7 +615,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -844,7 +644,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -863,7 +663,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -892,7 +692,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json b/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json
index 41349d3e..7691f5c 100644
--- a/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/ci/tvos-rel-fyi/targets/chromium.fyi.json
@@ -4,7 +4,8 @@
       "base_unittests",
       "components_unittests",
       "content_shell",
-      "content_unittests"
+      "content_unittests",
+      "media_unittests"
     ],
     "isolated_scripts": [
       {
@@ -156,6 +157,56 @@
         "test": "content_unittests",
         "test_id_prefix": "ninja://content/test:content_unittests/",
         "variant_id": "Apple TV 4K (3rd generation) 18.5"
+      },
+      {
+        "args": [
+          "--test-launcher-bot-mode",
+          "--test-launcher-filter-file=testing/buildbot/filters/ios.media_unittests.filter",
+          "--platform",
+          "Apple TV 4K (3rd generation)",
+          "--version",
+          "18.5",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "16f6",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "media_unittests Apple TV 4K (3rd generation) 18.5",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_tvos_18_5",
+              "path": "Runtime-tvos-18.5"
+            },
+            {
+              "name": "xcode_ios_16f6",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "media_unittests",
+        "test_id_prefix": "ninja://media:media_unittests/",
+        "variant_id": "Apple TV 4K (3rd generation) 18.5"
       }
     ]
   }
diff --git a/infra/config/generated/builders/gn_args_locations.json b/infra/config/generated/builders/gn_args_locations.json
index ed2260c..ac9fb6b8 100644
--- a/infra/config/generated/builders/gn_args_locations.json
+++ b/infra/config/generated/builders/gn_args_locations.json
@@ -295,6 +295,7 @@
     "Libfuzzer Upload iOS Catalyst Debug": "ci/Libfuzzer Upload iOS Catalyst Debug/gn-args.json",
     "MSAN Release (chained origins)": "ci/MSAN Release (chained origins)/gn-args.json",
     "MSAN Release (no origins)": "ci/MSAN Release (no origins)/gn-args.json",
+    "Mac ARM64 ASAN Release": "ci/Mac ARM64 ASAN Release/gn-args.json",
     "Mac ASAN Release": "ci/Mac ASAN Release/gn-args.json",
     "Mac ASAN Release Media": "ci/Mac ASAN Release Media/gn-args.json",
     "TSAN Debug": "ci/TSAN Debug/gn-args.json",
@@ -750,6 +751,7 @@
     "linux-tsan-rel": "try/linux-tsan-rel/gn-args.json",
     "linux-ubsan-rel": "try/linux-ubsan-rel/gn-args.json",
     "linux-ubsan-vptr-rel": "try/linux-ubsan-vptr-rel/gn-args.json",
+    "mac-arm64-asan-rel": "try/mac-arm64-asan-rel/gn-args.json",
     "mac-asan-media-rel": "try/mac-asan-media-rel/gn-args.json",
     "mac-asan-rel": "try/mac-asan-rel/gn-args.json",
     "win-asan-media-rel": "try/win-asan-media-rel/gn-args.json",
diff --git a/infra/config/generated/builders/try/ios-blink-rel-fyi/properties.json b/infra/config/generated/builders/try/ios-blink-rel-fyi/properties.json
index f796d785..bb140c41 100644
--- a/infra/config/generated/builders/try/ios-blink-rel-fyi/properties.json
+++ b/infra/config/generated/builders/try/ios-blink-rel-fyi/properties.json
@@ -64,5 +64,5 @@
   },
   "builder_group": "tryserver.chromium.mac",
   "recipe": "chromium_trybot",
-  "xcode_build_version": "17a5276g"
+  "xcode_build_version": "17a5285i"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/ios-blink-rel-fyi/targets/chromium.fyi.json b/infra/config/generated/builders/try/ios-blink-rel-fyi/targets/chromium.fyi.json
index a095063a..da7e5d0b 100644
--- a/infra/config/generated/builders/try/ios-blink-rel-fyi/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/try/ios-blink-rel-fyi/targets/chromium.fyi.json
@@ -13,7 +13,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -42,7 +42,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -61,7 +61,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -90,7 +90,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -112,7 +112,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -141,7 +141,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -160,7 +160,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -189,7 +189,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -208,7 +208,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -237,7 +237,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -256,7 +256,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -285,7 +285,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -307,7 +307,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -341,7 +341,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -360,7 +360,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -389,7 +389,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -408,7 +408,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -437,7 +437,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -456,7 +456,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -485,7 +485,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -504,7 +504,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -533,7 +533,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -555,7 +555,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -584,7 +584,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -605,7 +605,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -634,7 +634,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -655,7 +655,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -684,7 +684,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -705,7 +705,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -734,7 +734,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -755,7 +755,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -784,7 +784,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -806,7 +806,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -835,7 +835,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -854,7 +854,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -883,7 +883,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -902,7 +902,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -931,7 +931,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -950,7 +950,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -979,7 +979,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -998,7 +998,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1027,7 +1027,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1046,7 +1046,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1075,7 +1075,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1094,7 +1094,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1123,7 +1123,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1142,7 +1142,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1171,7 +1171,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1192,7 +1192,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1221,7 +1221,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1240,7 +1240,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1269,7 +1269,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1288,7 +1288,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1317,7 +1317,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1336,7 +1336,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1365,7 +1365,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1386,7 +1386,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1415,7 +1415,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1434,7 +1434,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1463,7 +1463,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1482,7 +1482,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1511,7 +1511,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1530,7 +1530,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1559,7 +1559,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1578,7 +1578,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1607,7 +1607,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1626,7 +1626,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1655,7 +1655,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1676,7 +1676,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1705,7 +1705,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1730,7 +1730,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1759,7 +1759,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1784,7 +1784,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1813,7 +1813,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1832,7 +1832,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1861,7 +1861,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1882,7 +1882,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1911,7 +1911,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1930,7 +1930,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1959,7 +1959,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1978,7 +1978,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2007,7 +2007,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2026,7 +2026,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2055,7 +2055,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2074,7 +2074,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2103,7 +2103,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2122,7 +2122,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2151,7 +2151,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2171,7 +2171,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2200,7 +2200,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2219,7 +2219,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2248,7 +2248,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2267,7 +2267,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2296,7 +2296,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2315,7 +2315,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2344,7 +2344,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2363,7 +2363,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2392,7 +2392,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2412,7 +2412,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2441,7 +2441,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2460,7 +2460,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2489,7 +2489,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2508,7 +2508,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2537,7 +2537,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2556,7 +2556,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2585,7 +2585,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2607,7 +2607,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2636,7 +2636,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2655,7 +2655,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2684,7 +2684,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2703,7 +2703,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2732,7 +2732,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/try/ios18-sdk-simulator/properties.json b/infra/config/generated/builders/try/ios18-sdk-simulator/properties.json
index 7e03518..3321b37 100644
--- a/infra/config/generated/builders/try/ios18-sdk-simulator/properties.json
+++ b/infra/config/generated/builders/try/ios18-sdk-simulator/properties.json
@@ -63,5 +63,5 @@
   },
   "builder_group": "tryserver.chromium.mac",
   "recipe": "chromium_trybot",
-  "xcode_build_version": "17a5276g"
+  "xcode_build_version": "17a5285i"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/ios18-sdk-simulator/targets/chromium.fyi.json b/infra/config/generated/builders/try/ios18-sdk-simulator/targets/chromium.fyi.json
index c59bc20..5e870a3 100644
--- a/infra/config/generated/builders/try/ios18-sdk-simulator/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/try/ios18-sdk-simulator/targets/chromium.fyi.json
@@ -13,7 +13,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -42,7 +42,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -61,7 +61,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -90,7 +90,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -109,7 +109,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -138,7 +138,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -157,7 +157,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -186,7 +186,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -205,7 +205,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -234,7 +234,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -253,7 +253,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -282,7 +282,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -301,7 +301,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -330,7 +330,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -349,7 +349,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -378,7 +378,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -397,7 +397,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -426,7 +426,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -445,7 +445,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -474,7 +474,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -493,7 +493,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -522,7 +522,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -541,7 +541,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -570,7 +570,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -589,7 +589,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -618,7 +618,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -637,7 +637,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -666,7 +666,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -685,7 +685,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -714,7 +714,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -733,7 +733,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -762,7 +762,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -781,7 +781,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -810,7 +810,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -829,7 +829,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -858,7 +858,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -877,7 +877,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -906,7 +906,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -925,7 +925,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -954,7 +954,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -973,7 +973,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1002,7 +1002,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1024,7 +1024,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1053,7 +1053,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1076,7 +1076,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1105,7 +1105,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1128,7 +1128,111 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_signin_eg2tests_module iPad Air (5th generation) 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "ios_chrome_signin_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
+        "variant_id": "iPad Air (5th generation) 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPhone 14",
+          "--version",
+          "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_signin_eg2tests_module iPhone 14 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "ios_chrome_signin_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
+        "variant_id": "iPhone 14 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPad Air (5th generation)",
+          "--version",
+          "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1157,7 +1261,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1179,7 +1283,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1208,7 +1312,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1227,7 +1331,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1256,7 +1360,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1275,7 +1379,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1304,7 +1408,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1323,7 +1427,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1352,7 +1456,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1368,10 +1472,114 @@
           "iPad Air (5th generation)",
           "--version",
           "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_web_eg2tests_module iPad Air (5th generation) 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "ios_chrome_web_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
+        "variant_id": "iPad Air (5th generation) 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPhone 14",
+          "--version",
+          "26.0",
+          "--xcodebuild-sim-runner",
+          "--record-video",
+          "failed_only",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "ios_chrome_web_eg2tests_module iPhone 14 26.0",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15.5"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_ios_26_0",
+              "path": "Runtime-ios-26.0"
+            },
+            {
+              "name": "xcode_ios_17a5285i",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "ios_chrome_web_eg2tests_module",
+        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
+        "variant_id": "iPhone 14 26.0"
+      },
+      {
+        "args": [
+          "--platform",
+          "iPad Air (5th generation)",
+          "--version",
+          "26.0",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1400,7 +1608,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1419,7 +1627,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1448,7 +1656,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1468,7 +1676,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1497,7 +1705,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1517,7 +1725,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1546,7 +1754,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1565,7 +1773,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1594,7 +1802,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1614,7 +1822,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1643,7 +1851,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1663,7 +1871,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1692,7 +1900,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1711,7 +1919,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1740,7 +1948,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1759,7 +1967,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1788,7 +1996,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1807,7 +2015,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1836,7 +2044,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1855,7 +2063,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1884,7 +2092,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1903,7 +2111,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1932,7 +2140,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1951,7 +2159,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1980,7 +2188,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1999,7 +2207,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2028,7 +2236,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2047,7 +2255,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2076,7 +2284,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2095,7 +2303,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2124,7 +2332,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2143,7 +2351,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2172,7 +2380,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2191,7 +2399,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2220,7 +2428,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2239,7 +2447,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2268,7 +2476,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2287,7 +2495,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2316,7 +2524,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2335,7 +2543,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2364,7 +2572,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2383,7 +2591,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2412,7 +2620,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2431,7 +2639,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2460,7 +2668,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2479,7 +2687,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2508,7 +2716,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2527,7 +2735,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2556,7 +2764,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2575,7 +2783,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2604,7 +2812,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2623,7 +2831,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2652,7 +2860,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2671,7 +2879,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2700,7 +2908,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/try/ios26-beta-simulator/targets/chromium.fyi.json b/infra/config/generated/builders/try/ios26-beta-simulator/targets/chromium.fyi.json
index 6179de37..bca42ac 100644
--- a/infra/config/generated/builders/try/ios26-beta-simulator/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/try/ios26-beta-simulator/targets/chromium.fyi.json
@@ -13,7 +13,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -42,7 +42,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -61,7 +61,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -90,7 +90,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -109,7 +109,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -138,7 +138,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -157,7 +157,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -186,7 +186,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -205,7 +205,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -234,7 +234,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -253,7 +253,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -282,7 +282,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -301,7 +301,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -330,7 +330,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -349,7 +349,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -378,7 +378,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -397,7 +397,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -426,7 +426,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -445,7 +445,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -474,7 +474,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -493,7 +493,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -522,7 +522,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -541,7 +541,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -570,7 +570,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -589,7 +589,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -618,7 +618,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -637,7 +637,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -666,7 +666,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -685,7 +685,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -714,7 +714,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -733,7 +733,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -762,7 +762,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -781,7 +781,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -810,7 +810,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -829,7 +829,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -858,7 +858,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -877,7 +877,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -906,7 +906,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -925,7 +925,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -954,7 +954,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -973,7 +973,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1002,7 +1002,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1024,7 +1024,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1053,7 +1053,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1076,7 +1076,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1105,7 +1105,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1130,7 +1130,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1159,7 +1159,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1184,7 +1184,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1213,7 +1213,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1238,7 +1238,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1267,7 +1267,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1292,7 +1292,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1321,7 +1321,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1344,7 +1344,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1373,7 +1373,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1396,7 +1396,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1425,7 +1425,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1448,7 +1448,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1477,7 +1477,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1499,7 +1499,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1528,7 +1528,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1552,7 +1552,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1581,7 +1581,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1606,7 +1606,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1635,7 +1635,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1655,7 +1655,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1684,7 +1684,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1703,7 +1703,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1732,7 +1732,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1751,7 +1751,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1780,7 +1780,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1802,7 +1802,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1831,7 +1831,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1854,7 +1854,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1883,7 +1883,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1903,7 +1903,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1932,7 +1932,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -1951,7 +1951,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -1980,7 +1980,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2000,7 +2000,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2029,7 +2029,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2049,7 +2049,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2078,7 +2078,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2097,7 +2097,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2126,7 +2126,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2146,7 +2146,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2175,7 +2175,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2195,7 +2195,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2224,7 +2224,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2243,7 +2243,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2272,7 +2272,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2291,7 +2291,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2320,7 +2320,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2339,7 +2339,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2368,7 +2368,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2387,7 +2387,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2416,7 +2416,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2438,7 +2438,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2467,7 +2467,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2489,7 +2489,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2518,7 +2518,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2537,7 +2537,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2566,7 +2566,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2585,7 +2585,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2614,7 +2614,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2633,7 +2633,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2662,7 +2662,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2681,7 +2681,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2710,7 +2710,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2729,7 +2729,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2758,7 +2758,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2777,7 +2777,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2806,7 +2806,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2825,7 +2825,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2854,7 +2854,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2873,7 +2873,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2902,7 +2902,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2921,7 +2921,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2950,7 +2950,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -2969,7 +2969,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -2998,7 +2998,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3017,7 +3017,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3046,7 +3046,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3065,7 +3065,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3094,7 +3094,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3113,7 +3113,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3142,7 +3142,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3161,7 +3161,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3190,7 +3190,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3209,7 +3209,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3238,7 +3238,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3257,7 +3257,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3286,7 +3286,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3305,7 +3305,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3334,7 +3334,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3353,7 +3353,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3382,7 +3382,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3401,7 +3401,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3430,7 +3430,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3449,7 +3449,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3478,7 +3478,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3497,7 +3497,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3526,7 +3526,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3545,7 +3545,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3574,7 +3574,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -3593,7 +3593,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -3622,7 +3622,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/try/ios26-sdk-simulator/properties.json b/infra/config/generated/builders/try/ios26-sdk-simulator/properties.json
index f100e53a..4dd3bf5 100644
--- a/infra/config/generated/builders/try/ios26-sdk-simulator/properties.json
+++ b/infra/config/generated/builders/try/ios26-sdk-simulator/properties.json
@@ -63,5 +63,5 @@
   },
   "builder_group": "tryserver.chromium.mac",
   "recipe": "chromium_trybot",
-  "xcode_build_version": "17a5276g"
+  "xcode_build_version": "17a5285i"
 }
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/ios26-sdk-simulator/targets/chromium.fyi.json b/infra/config/generated/builders/try/ios26-sdk-simulator/targets/chromium.fyi.json
index ba0f4af..9843a5f5 100644
--- a/infra/config/generated/builders/try/ios26-sdk-simulator/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/try/ios26-sdk-simulator/targets/chromium.fyi.json
@@ -16,7 +16,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -45,7 +45,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -68,7 +68,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -97,7 +97,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -120,7 +120,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -149,7 +149,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -172,7 +172,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -201,7 +201,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -214,106 +214,6 @@
       },
       {
         "args": [
-          "--platform",
-          "iPad Air (5th generation)",
-          "--version",
-          "26.0",
-          "--xcodebuild-sim-runner",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_signin_eg2tests_module iPad Air (5th generation) 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "ios_chrome_signin_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPad Air (5th generation) 26.0"
-      },
-      {
-        "args": [
-          "--platform",
-          "iPhone 14",
-          "--version",
-          "26.0",
-          "--xcodebuild-sim-runner",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_signin_eg2tests_module iPhone 14 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "ios_chrome_signin_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_signin_eg2tests_module/",
-        "variant_id": "iPhone 14 26.0"
-      },
-      {
-        "args": [
           "--clones",
           "2",
           "--platform",
@@ -324,7 +224,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -353,7 +253,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -376,7 +276,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -405,7 +305,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -422,110 +322,10 @@
           "iPad Air (5th generation)",
           "--version",
           "26.0",
-          "--xcodebuild-sim-runner",
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_web_eg2tests_module iPad Air (5th generation) 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "ios_chrome_web_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPad Air (5th generation) 26.0"
-      },
-      {
-        "args": [
-          "--platform",
-          "iPhone 14",
-          "--version",
-          "26.0",
-          "--xcodebuild-sim-runner",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
-          "--xctest"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "ios_chrome_web_eg2tests_module iPhone 14 26.0",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/mac_toolchain/${platform}",
-              "location": ".",
-              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
-            }
-          ],
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-15.5"
-          },
-          "named_caches": [
-            {
-              "name": "runtime_ios_26_0",
-              "path": "Runtime-ios-26.0"
-            },
-            {
-              "name": "xcode_ios_17a5241o",
-              "path": "Xcode.app"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "ios_chrome_web_eg2tests_module",
-        "test_id_prefix": "ninja://ios/chrome/test/earl_grey2:ios_chrome_web_eg2tests_module/",
-        "variant_id": "iPhone 14 26.0"
-      },
-      {
-        "args": [
-          "--platform",
-          "iPad Air (5th generation)",
-          "--version",
-          "26.0",
-          "--out-dir",
-          "${ISOLATED_OUTDIR}",
-          "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -554,7 +354,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -573,7 +373,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -602,7 +402,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -621,7 +421,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -650,7 +450,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -670,7 +470,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -699,7 +499,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -719,7 +519,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -748,7 +548,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -767,7 +567,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -796,7 +596,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -815,7 +615,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -844,7 +644,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
@@ -863,7 +663,7 @@
           "--out-dir",
           "${ISOLATED_OUTDIR}",
           "--xcode-build-version",
-          "17a5241o",
+          "17a5285i",
           "--xctest"
         ],
         "merge": {
@@ -892,7 +692,7 @@
               "path": "Runtime-ios-26.0"
             },
             {
-              "name": "xcode_ios_17a5241o",
+              "name": "xcode_ios_17a5285i",
               "path": "Xcode.app"
             }
           ],
diff --git a/infra/config/generated/builders/try/mac-arm64-asan-rel/gn-args.json b/infra/config/generated/builders/try/mac-arm64-asan-rel/gn-args.json
new file mode 100644
index 0000000..a42bd352
--- /dev/null
+++ b/infra/config/generated/builders/try/mac-arm64-asan-rel/gn-args.json
@@ -0,0 +1,15 @@
+{
+  "gn_args": {
+    "dcheck_always_on": false,
+    "enable_ipc_fuzzer": true,
+    "is_asan": true,
+    "is_component_build": false,
+    "is_debug": false,
+    "target_cpu": "arm64",
+    "target_os": "mac",
+    "use_reclient": false,
+    "use_remoteexec": true,
+    "use_siso": true,
+    "v8_enable_verify_heap": true
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac-arm64-asan-rel/properties.json b/infra/config/generated/builders/try/mac-arm64-asan-rel/properties.json
new file mode 100644
index 0000000..793c940
--- /dev/null
+++ b/infra/config/generated/builders/try/mac-arm64-asan-rel/properties.json
@@ -0,0 +1,73 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "additional_exclusions": [
+        "infra/config/generated/builders/try/mac-arm64-asan-rel/gn-args.json"
+      ],
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Mac ARM64 ASAN Release",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "builder_group": "chromium.fuzz",
+              "clusterfuzz_archive": {
+                "archive_name_prefix": "asan",
+                "archive_subdir": "arm64",
+                "gs_acl": "public-read",
+                "gs_bucket": "chromium-browser-asan"
+              },
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "clobber",
+                  "mb"
+                ],
+                "build_config": "Release",
+                "config": "chromium_asan",
+                "target_arch": "arm",
+                "target_bits": 64,
+                "target_platform": "mac"
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Mac ARM64 ASAN Release",
+          "project": "chromium"
+        }
+      ],
+      "targets_spec_directory": "src/infra/config/generated/builders/try/mac-arm64-asan-rel/targets"
+    }
+  },
+  "$build/siso": {
+    "configs": [
+      "builder"
+    ],
+    "enable_cloud_monitoring": true,
+    "enable_cloud_profiler": true,
+    "enable_cloud_trace": true,
+    "experiments": [],
+    "metrics_project": "chromium-reclient-metrics",
+    "project": "rbe-chromium-untrusted",
+    "remote_jobs": -1
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.fuzz",
+  "recipe": "chromium_trybot"
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac-arm64-asan-rel/targets/chromium.fuzz.json b/infra/config/generated/builders/try/mac-arm64-asan-rel/targets/chromium.fuzz.json
new file mode 100644
index 0000000..4de8fb8
--- /dev/null
+++ b/infra/config/generated/builders/try/mac-arm64-asan-rel/targets/chromium.fuzz.json
@@ -0,0 +1,7 @@
+{
+  "Mac ARM64 ASAN Release": {
+    "additional_compile_targets": [
+      "chromium_builder_asan"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json b/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json
index 41349d3e..7691f5c 100644
--- a/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json
+++ b/infra/config/generated/builders/try/tvos-rel-fyi/targets/chromium.fyi.json
@@ -4,7 +4,8 @@
       "base_unittests",
       "components_unittests",
       "content_shell",
-      "content_unittests"
+      "content_unittests",
+      "media_unittests"
     ],
     "isolated_scripts": [
       {
@@ -156,6 +157,56 @@
         "test": "content_unittests",
         "test_id_prefix": "ninja://content/test:content_unittests/",
         "variant_id": "Apple TV 4K (3rd generation) 18.5"
+      },
+      {
+        "args": [
+          "--test-launcher-bot-mode",
+          "--test-launcher-filter-file=testing/buildbot/filters/ios.media_unittests.filter",
+          "--platform",
+          "Apple TV 4K (3rd generation)",
+          "--version",
+          "18.5",
+          "--out-dir",
+          "${ISOLATED_OUTDIR}",
+          "--xcode-build-version",
+          "16f6",
+          "--xctest"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "media_unittests Apple TV 4K (3rd generation) 18.5",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/mac_toolchain/${platform}",
+              "location": ".",
+              "revision": "git_revision:4c7290150d1c360cecc6a93c0214dc531585c3ab"
+            }
+          ],
+          "dimensions": {
+            "cpu": "arm64",
+            "os": "Mac-15"
+          },
+          "named_caches": [
+            {
+              "name": "runtime_tvos_18_5",
+              "path": "Runtime-tvos-18.5"
+            },
+            {
+              "name": "xcode_ios_16f6",
+              "path": "Xcode.app"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "media_unittests",
+        "test_id_prefix": "ninja://media:media_unittests/",
+        "variant_id": "Apple TV 4K (3rd generation) 18.5"
       }
     ]
   }
diff --git a/infra/config/generated/health-specs/health-specs.json b/infra/config/generated/health-specs/health-specs.json
index a6eb1c5..a33cd44 100644
--- a/infra/config/generated/health-specs/health-specs.json
+++ b/infra/config/generated/health-specs/health-specs.json
@@ -3649,6 +3649,27 @@
           }
         ]
       },
+      "Mac ARM64 ASAN Release": {
+        "contact_team_email": "chrome-sanitizer-builder-owners@google.com",
+        "problem_specs": [
+          {
+            "name": "Unhealthy",
+            "period_days": 7,
+            "score": 5,
+            "thresholds": {
+              "_default": "_default"
+            }
+          },
+          {
+            "name": "Low Value",
+            "period_days": 90,
+            "score": 1,
+            "thresholds": {
+              "_default": "_default"
+            }
+          }
+        ]
+      },
       "Mac ASAN Release": {
         "contact_team_email": "chrome-sanitizer-builder-owners@google.com",
         "problem_specs": [
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 8caa0ba..6c826f2 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -6194,6 +6194,11 @@
         disable_reuse_footers: "Include-Ci-Only-Tests"
       }
       builders {
+        name: "chromium/try/mac-arm64-asan-rel"
+        includable_only: true
+        disable_reuse_footers: "Include-Ci-Only-Tests"
+      }
+      builders {
         name: "chromium/try/mac-arm64-clobber-rel"
         includable_only: true
         disable_reuse_footers: "Include-Ci-Only-Tests"
@@ -7893,7 +7898,6 @@
       name: "chromium/src"
       ref_regexp: "refs/branch-heads/.*"
       ref_regexp_exclude: "refs/branch-heads/6834"
-      ref_regexp_exclude: "refs/branch-heads/7103"
       ref_regexp_exclude: "refs/branch-heads/7151"
       ref_regexp_exclude: "refs/branch-heads/7204"
       ref_regexp_exclude: "refs/branch-heads/7258"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index d36cfc2..90818366 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -21750,6 +21750,116 @@
       }
     }
     builders {
+      name: "Mac ARM64 ASAN Release"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:arm64"
+      dimensions: "free_space:standard"
+      dimensions: "os:Mac-15"
+      dimensions: "pool:luci.chromium.ci"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/ci/Mac ARM64 ASAN Release/properties.json",'
+        '    "shadow_properties_file": "infra/config/generated/builders/ci/Mac ARM64 ASAN Release/shadow-properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "chromium.fuzz",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium"'
+        '}'
+      execution_timeout_secs: 10800
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium.use_per_builder_build_dir_name"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome|content)/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)|(ninja://[^/]*headless_shell_wpt/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "ASAN build of chrome for Mac ARM64.<br/>This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/mac-arm64-asan-rel\">mac-arm64-asan-rel</a></li></ul><br/>Builder owner: <a href=mailto:chrome-sanitizer-builder-owners@google.com>chrome-sanitizer-builder-owners@google.com</a>"
+      shadow_builder_adjustments {
+        service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+        pool: "luci.chromium.try"
+        dimensions: "free_space:"
+        dimensions: "pool:luci.chromium.try"
+      }
+      contact_team_email: "chrome-sanitizer-builder-owners@google.com"
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/cached_count"
+        predicates: "has(build.output.properties.is_cached)"
+        predicates: "string(build.output.properties.is_cached) == \"true\""
+      }
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count"
+        predicates: "has(build.output.properties.ran_tests_retry_shard)"
+      }
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/ran_tests_without_patch_count"
+        predicates: "has(build.output.properties.ran_tests_without_patch)"
+      }
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/uncached_count"
+        predicates: "has(build.output.properties.is_cached)"
+        predicates: "string(build.output.properties.is_cached) == \"false\""
+      }
+    }
+    builders {
       name: "Mac ASAN Release"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -48832,8 +48942,8 @@
       priority: 35
       execution_timeout_secs: 10800
       caches {
-        name: "xcode_ios_17a5276g"
-        path: "xcode_ios_17a5276g.app"
+        name: "xcode_ios_17a5285i"
+        path: "xcode_ios_17a5285i.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -50336,8 +50446,8 @@
       priority: 35
       execution_timeout_secs: 36000
       caches {
-        name: "xcode_ios_17a5276g"
-        path: "xcode_ios_17a5276g.app"
+        name: "xcode_ios_17a5285i"
+        path: "xcode_ios_17a5285i.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -50562,8 +50672,8 @@
       priority: 35
       execution_timeout_secs: 36000
       caches {
-        name: "xcode_ios_17a5276g"
-        path: "xcode_ios_17a5276g.app"
+        name: "xcode_ios_17a5285i"
+        path: "xcode_ios_17a5285i.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -99342,8 +99452,8 @@
         seconds: 120
       }
       caches {
-        name: "xcode_ios_17a5276g"
-        path: "xcode_ios_17a5276g.app"
+        name: "xcode_ios_17a5285i"
+        path: "xcode_ios_17a5285i.app"
       }
       build_numbers: YES
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -100821,8 +100931,8 @@
         seconds: 120
       }
       caches {
-        name: "xcode_ios_17a5276g"
-        path: "xcode_ios_17a5276g.app"
+        name: "xcode_ios_17a5285i"
+        path: "xcode_ios_17a5285i.app"
       }
       build_numbers: YES
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -101045,8 +101155,8 @@
         seconds: 120
       }
       caches {
-        name: "xcode_ios_17a5276g"
-        path: "xcode_ios_17a5276g.app"
+        name: "xcode_ios_17a5285i"
+        path: "xcode_ios_17a5285i.app"
       }
       build_numbers: YES
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -113312,6 +113422,116 @@
       }
     }
     builders {
+      name: "mac-arm64-asan-rel"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cpu:arm64"
+      dimensions: "free_space:standard"
+      dimensions: "os:Mac-15"
+      dimensions: "pool:luci.chromium.try"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/try/mac-arm64-asan-rel/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.fuzz",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium.use_per_builder_build_dir_name"
+        value: 100
+      }
+      experiments {
+        key: "luci.buildbucket.canary_software"
+        value: 5
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome|content)/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)|(ninja://[^/]*headless_shell_wpt/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "<br>ASAN build of chrome for Mac ARM64.<br/><br/>This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Mac ARM64 ASAN Release\">Mac ARM64 ASAN Release</a></li></ul><br/>Builder owner: <a href=mailto:chrome-sanitizer-builder-owners@google.com>chrome-sanitizer-builder-owners@google.com</a>"
+      contact_team_email: "chrome-sanitizer-builder-owners@google.com"
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/cached_count"
+        predicates: "has(build.output.properties.is_cached)"
+        predicates: "string(build.output.properties.is_cached) == \"true\""
+      }
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count"
+        predicates: "has(build.output.properties.ran_tests_retry_shard)"
+      }
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/ran_tests_without_patch_count"
+        predicates: "has(build.output.properties.ran_tests_without_patch)"
+      }
+      custom_metric_definitions {
+        name: "/chrome/infra/browser/builds/uncached_count"
+        predicates: "has(build.output.properties.is_cached)"
+        predicates: "string(build.output.properties.is_cached) == \"false\""
+      }
+    }
+    builders {
       name: "mac-arm64-clobber-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 4577eb8..7b5bf563 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -347,10 +347,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -1288,10 +1284,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -2032,10 +2024,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -2606,10 +2594,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -2988,10 +2972,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -3846,10 +3826,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -4323,10 +4299,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -4760,10 +4732,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -5134,10 +5102,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -5511,10 +5475,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -5888,10 +5848,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -6330,10 +6286,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -7337,10 +7289,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -8109,10 +8057,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -8481,10 +8425,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -9137,10 +9077,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -9524,10 +9460,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -9891,10 +9823,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -10342,10 +10270,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -10779,10 +10703,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -11145,10 +11065,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -11665,10 +11581,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -12097,10 +12009,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -12704,10 +12612,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -13281,10 +13185,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -13908,10 +13808,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -14380,10 +14276,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -14774,10 +14666,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -14934,6 +14822,11 @@
     short_name: "rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Mac ARM64 ASAN Release"
+    category: "mac asan"
+    short_name: "arm64-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Mac ASAN Release Media"
     category: "mac asan"
     short_name: "med"
@@ -15316,10 +15209,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -15900,10 +15789,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -16323,10 +16208,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -17084,10 +16965,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -17479,10 +17356,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -18222,10 +18095,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -18633,10 +18502,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -19089,10 +18954,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -19556,10 +19417,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -20028,10 +19885,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -20400,10 +20253,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -20802,10 +20651,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -21209,10 +21054,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -21761,10 +21602,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -22163,10 +22000,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -22596,10 +22429,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -23033,10 +22862,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -23410,10 +23235,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -23787,10 +23608,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -24268,10 +24085,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -24875,10 +24688,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -25273,10 +25082,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -25682,10 +25487,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -26069,10 +25870,6 @@
         url: "/p/chromium-m132/g/main/console"
       }
       links {
-        text: "m136"
-        url: "/p/chromium-m136/g/main/console"
-      }
-      links {
         text: "m137"
         url: "/p/chromium-m137/g/main/console"
       }
@@ -27237,6 +27034,9 @@
     name: "buildbucket/luci.chromium.try/mac-angle-chromium-try"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/mac-arm64-asan-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/mac-arm64-clobber-rel"
   }
   builders {
@@ -28412,6 +28212,9 @@
     name: "buildbucket/luci.chromium.try/linux-ubsan-vptr-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/mac-arm64-asan-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/mac-asan-media-rel"
   }
   builders {
diff --git a/infra/config/generated/luci/luci-notify.cfg b/infra/config/generated/luci/luci-notify.cfg
index f1e32b4b..f9845141 100644
--- a/infra/config/generated/luci/luci-notify.cfg
+++ b/infra/config/generated/luci/luci-notify.cfg
@@ -1219,6 +1219,19 @@
   }
   builders {
     bucket: "ci"
+    name: "Mac ARM64 ASAN Release"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+}
+notifiers {
+  notifications {
+    on_change: true
+    email {
+      recipients: "chrome-fuzzing-core+bots@google.com"
+    }
+  }
+  builders {
+    bucket: "ci"
     name: "Mac ASAN Release"
     repository: "https://chromium.googlesource.com/chromium/src"
   }
@@ -4179,6 +4192,7 @@
 tree_closing_enabled: true
 builder_health_notifier {
   owner_email: "chrome-browser-infra-team@google.com"
+  notify_all_healthy: true
   builders {
     bucket: "ci"
     name: "3pp-windows-amd64-packager"
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index e07865d..7ce2ae5 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -1657,6 +1657,19 @@
   }
 }
 job {
+  id: "Mac ARM64 ASAN Release"
+  realm: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 1
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "Mac ARM64 ASAN Release"
+  }
+}
+job {
   id: "Mac ASAN Release"
   realm: "ci"
   triggering_policy {
@@ -6258,6 +6271,7 @@
   triggers: "Linux Viz"
   triggers: "MSAN Release (chained origins)"
   triggers: "MSAN Release (no origins)"
+  triggers: "Mac ARM64 ASAN Release"
   triggers: "Mac ASAN Release"
   triggers: "Mac ASAN Release Media"
   triggers: "Mac ASan 64 Builder"
diff --git a/infra/config/generated/luci/realms.cfg b/infra/config/generated/luci/realms.cfg
index d5e3230..ff96d0c 100644
--- a/infra/config/generated/luci/realms.cfg
+++ b/infra/config/generated/luci/realms.cfg
@@ -550,7 +550,6 @@
     principals: "group:mdb/chrome-build-access-sphinx"
     principals: "project:angle"
     principals: "project:chromium-m132"
-    principals: "project:chromium-m136"
     principals: "project:chromium-m137"
     principals: "project:chromium-m138"
     principals: "project:chromium-m139"
@@ -606,7 +605,6 @@
     principals: "project:angle"
     principals: "project:chromium-infra"
     principals: "project:chromium-m132"
-    principals: "project:chromium-m136"
     principals: "project:chromium-m137"
     principals: "project:chromium-m138"
     principals: "project:chromium-m139"
diff --git a/infra/config/lib/xcode.star b/infra/config/lib/xcode.star
index 1a84fdb..c21a550 100644
--- a/infra/config/lib/xcode.star
+++ b/infra/config/lib/xcode.star
@@ -24,7 +24,7 @@
     # Xcode 16 beta version used on beta bots.
     x16betabots = _xcode.for_ios("16f6"),
     # Xcode 26 beta version used on beta bots.
-    x26betabots = _xcode.for_ios("17a5276g"),
+    x26betabots = _xcode.for_ios("17a5285i"),
     # in use by ios-webkit-tot
     x14wk = _xcode.for_ios("14c18wk"),
 )
diff --git a/infra/config/milestones.json b/infra/config/milestones.json
index b06f431..9911f33 100644
--- a/infra/config/milestones.json
+++ b/infra/config/milestones.json
@@ -4,11 +4,6 @@
         "project": "chromium-m132",
         "ref": "refs/branch-heads/6834"
     },
-    "136": {
-        "name": "m136",
-        "project": "chromium-m136",
-        "ref": "refs/branch-heads/7103"
-    },
     "137": {
         "name": "m137",
         "project": "chromium-m137",
diff --git a/infra/config/notifiers.star b/infra/config/notifiers.star
index d4f8ad05..3ed6b39 100644
--- a/infra/config/notifiers.star
+++ b/infra/config/notifiers.star
@@ -367,4 +367,5 @@
 luci.builder_health_notifier(
     owner_email = "chrome-browser-infra-team@google.com",
     ignore_buckets = ["try"],
+    notify_all_healthy = True,
 )
diff --git a/infra/config/subprojects/chromium/ci/chromium.fuzz.star b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
index d19fa96..b4a0c86 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fuzz.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fuzz.star
@@ -78,6 +78,7 @@
         chromium_config_name = None,
         build_config = None,
         target_bits = None,
+        target_arch = None,
         target_platform = None,
         chromium_extra_apply_configs = [],
         gclient_apply_configs = None,
@@ -103,7 +104,10 @@
     if target_bits == 32:
         gn_configs.append("x86")
     elif target_bits == 64:
-        gn_configs.append("x64")
+        if target_arch == builder_config.target_arch.ARM:
+            gn_configs.append("arm64")
+        else:
+            gn_configs.append("x64")
 
     if target_platform == builder_config.target_platform.CHROMEOS:
         gn_configs.append("chromeos")
@@ -129,6 +133,7 @@
                     "mb",
                 ] + chromium_extra_apply_configs),
                 build_config = build_config,
+                target_arch = target_arch,
                 target_bits = target_bits,
                 target_platform = target_platform,
             ),
@@ -644,9 +649,10 @@
 
 def browser_asan_mac_builder(
         gn_extra_configs = [],
+        max_concurrent_invocations = 2,
         **kwargs):
     return browser_asan_builder(
-        max_concurrent_invocations = 2,
+        max_concurrent_invocations = max_concurrent_invocations,
         build_config = builder_config.build_config.RELEASE,
         target_bits = 64,
         target_platform = builder_config.target_platform.MAC,
@@ -682,6 +688,23 @@
     ],
 )
 
+browser_asan_mac_builder(
+    name = "Mac ARM64 ASAN Release",
+    description_html = "ASAN build of chrome for Mac ARM64.",
+    builderless = True,
+    cpu = cpu.ARM64,
+    # TODO(https://crbug.com/431089339): Add to gardening rotation once the build
+    # is proven green.
+    gardener_rotations = args.ignore_default(None),
+    target_arch = builder_config.target_arch.ARM,
+    # Full subdir: `mac-release-arm64`
+    clusterfuzz_archive_subdir = "arm64",
+    console_short_name = "arm64-rel",
+    contact_team_email = "chrome-sanitizer-builder-owners@google.com",
+    # We requested a single machine in https://crbug.com/432473774.
+    max_concurrent_invocations = 1,
+)
+
 def browser_tsan_builder(**kwargs):
     return browser_builder(
         chromium_config_name = "chromium_clang",
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 33e78d0c..df49b38 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -1630,6 +1630,7 @@
             "content_shell",
             "components_unittests",
             "content_unittests",
+            "media_unittests",
         ],
         mixins = [
             "expand-as-isolated-script",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star
index 289baf2..91468d68 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuzz.star
@@ -122,6 +122,16 @@
 )
 
 try_.builder(
+    name = "mac-arm64-asan-rel",
+    mirrors = ["ci/Mac ARM64 ASAN Release"],
+    gn_args = "ci/Mac ARM64 ASAN Release",
+    cores = None,
+    os = os.MAC_DEFAULT,
+    cpu = cpu.ARM64,
+    contact_team_email = "chrome-sanitizer-builder-owners@google.com",
+)
+
+try_.builder(
     name = "mac-asan-media-rel",
     mirrors = ["ci/Mac ASAN Release Media"],
     gn_args = "ci/Mac ASAN Release Media",
diff --git a/infra/config/targets/bundles.star b/infra/config/targets/bundles.star
index 89a6004..24ce8a5 100644
--- a/infra/config/targets/bundles.star
+++ b/infra/config/targets/bundles.star
@@ -5467,9 +5467,7 @@
     name = "ios_failing_eg2_tests",
     targets = [
         "ios_chrome_settings_eg2tests_module",
-        "ios_chrome_signin_eg2tests_module",
         "ios_chrome_ui_eg2tests_module",
-        "ios_chrome_web_eg2tests_module",
     ],
     per_test_modifications = {
         "ios_chrome_settings_eg2tests_module": [
@@ -5480,11 +5478,6 @@
             ),
             "ios_parallel_simulators",
         ],
-        "ios_chrome_signin_eg2tests_module": targets.mixin(
-            swarming = targets.swarming(
-                shards = 6,
-            ),
-        ),
         "ios_chrome_ui_eg2tests_module": [
             targets.mixin(
                 swarming = targets.swarming(
@@ -5493,11 +5486,6 @@
             ),
             "ios_parallel_simulators",
         ],
-        "ios_chrome_web_eg2tests_module": targets.mixin(
-            swarming = targets.swarming(
-                shards = 2,
-            ),
-        ),
     },
 )
 
@@ -5563,7 +5551,9 @@
     name = "ios_passing_eg2_tests",
     targets = [
         "ios_chrome_bookmarks_eg2tests_module",
+        "ios_chrome_signin_eg2tests_module",
         "ios_chrome_smoke_eg2tests_module",
+        "ios_chrome_web_eg2tests_module",
     ],
     per_test_modifications = {
         "ios_chrome_bookmarks_eg2tests_module": targets.mixin(
@@ -5571,6 +5561,16 @@
                 shards = 3,
             ),
         ),
+        "ios_chrome_signin_eg2tests_module": targets.mixin(
+            swarming = targets.swarming(
+                shards = 6,
+            ),
+        ),
+        "ios_chrome_web_eg2tests_module": targets.mixin(
+            swarming = targets.swarming(
+                shards = 2,
+            ),
+        ),
     },
 )
 
@@ -6846,6 +6846,7 @@
         "base_unittests",
         "components_unittests",
         "content_unittests",
+        "media_unittests",
     ],
     per_test_modifications = {
         "base_unittests": targets.mixin(
@@ -6866,6 +6867,12 @@
                 "--test-launcher-filter-file=testing/buildbot/filters/ios.content_unittests.filter",
             ],
         ),
+        "media_unittests": targets.mixin(
+            args = [
+                "--test-launcher-bot-mode",
+                "--test-launcher-filter-file=testing/buildbot/filters/ios.media_unittests.filter",
+            ],
+        ),
     },
 )
 
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star
index ff7f3d3..2088994 100644
--- a/infra/config/targets/mixins.star
+++ b/infra/config/targets/mixins.star
@@ -2659,12 +2659,12 @@
     generate_pyl_entry = False,
     args = [
         "--xcode-build-version",
-        "17a5241o",
+        "17a5285i",
     ],
     swarming = targets.swarming(
         named_caches = [
             swarming.cache(
-                name = "xcode_ios_17a5241o",
+                name = "xcode_ios_17a5285i",
                 path = "Xcode.app",
             ),
         ],
diff --git a/internal b/internal
index 14b33cf..c304aaa 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 14b33cf65221763eca19425d16d0bc106700f615
+Subproject commit c304aaac9c9d482c3e072b45e8f02397bd1aa810
diff --git a/ios/chrome/app/credential_provider_migrator_app_agent.mm b/ios/chrome/app/credential_provider_migrator_app_agent.mm
index 48bd2656..5d17975d 100644
--- a/ios/chrome/app/credential_provider_migrator_app_agent.mm
+++ b/ios/chrome/app/credential_provider_migrator_app_agent.mm
@@ -217,7 +217,7 @@
 
   password_manager::PasswordForm::Store defaultStore =
       password_manager::features_util::IsAccountStorageEnabled(
-          profile->GetPrefs(), SyncServiceFactory::GetForProfile(profile))
+          SyncServiceFactory::GetForProfile(profile))
           ? password_manager::PasswordForm::Store::kAccountStore
           : password_manager::PasswordForm::Store::kProfileStore;
   scoped_refptr<password_manager::PasswordStoreInterface> storeToSave =
diff --git a/ios/chrome/app/launch_screen_view_controller.mm b/ios/chrome/app/launch_screen_view_controller.mm
index a396a9bd..621553c8 100644
--- a/ios/chrome/app/launch_screen_view_controller.mm
+++ b/ios/chrome/app/launch_screen_view_controller.mm
@@ -16,7 +16,6 @@
 constexpr CGFloat kLogoMultiplier = 0.381966;
 constexpr CGFloat kBrandWidth = 107;
 constexpr CGFloat kStatusWidth = 195;
-constexpr CGFloat kLogoSize = 192;
 }  // namespace
 
 @interface LaunchScreenViewController ()
@@ -52,20 +51,12 @@
 
   [view addSubview:mainStackView];
 
-  NSLayoutConstraint* widthConstraint =
-      [logo.widthAnchor constraintLessThanOrEqualToConstant:kLogoSize];
-  widthConstraint.priority = UILayoutPriorityRequired - 1;
-
   [NSLayoutConstraint activateConstraints:@[
-    [logo.widthAnchor constraintLessThanOrEqualToAnchor:view.widthAnchor
-                                             multiplier:kLogoMultiplier],
-    [logo.heightAnchor constraintLessThanOrEqualToAnchor:view.heightAnchor
-                                              multiplier:kLogoMultiplier],
-    widthConstraint,
-    [logo.widthAnchor constraintEqualToAnchor:logo.heightAnchor],
+    [logo.widthAnchor constraintEqualToAnchor:view.widthAnchor
+                                   multiplier:kLogoMultiplier],
     [logo.centerYAnchor constraintEqualToAnchor:view.centerYAnchor],
     [brand.bottomAnchor
-        constraintEqualToAnchor:view.safeAreaLayoutGuide.bottomAnchor
+        constraintEqualToAnchor:view.layoutMarginsGuide.bottomAnchor
                        constant:-kBottomMargin],
     [brand.widthAnchor constraintEqualToConstant:kBrandWidth],
     [mainStackView.widthAnchor constraintEqualToAnchor:view.widthAnchor],
diff --git a/ios/chrome/app/resources/BUILD.gn b/ios/chrome/app/resources/BUILD.gn
index e2379d4..321882d 100644
--- a/ios/chrome/app/resources/BUILD.gn
+++ b/ios/chrome/app/resources/BUILD.gn
@@ -16,7 +16,7 @@
 
 group("resources") {
   public_deps = [
-    ":launchscreen",
+    ":launchscreen_xib",
     ":quick_action_icons",
     ":system_strings",
     "//ios/chrome/app/resources:packed_resources",
@@ -179,13 +179,8 @@
   ]
 }
 
-bundle_data_storyboard_file("launchscreen") {
-  source = "LaunchScreen.storyboard"
-  bundle_files = [
-    "Info.plist",
-    "Y6W-OH-hqX-view-5EZ-qb-Rvc.nib",
-    "UIViewController-Y6W-OH-hqX.nib",
-  ]
+bundle_data_xib_file("launchscreen_xib") {
+  source = "LaunchScreen.xib"
   deps = [ ios_launchscreen_assets_target ]
 }
 
diff --git a/ios/chrome/app/resources/Info.plist b/ios/chrome/app/resources/Info.plist
index 30454be..3d37f73 100644
--- a/ios/chrome/app/resources/Info.plist
+++ b/ios/chrome/app/resources/Info.plist
@@ -174,7 +174,7 @@
 		</dict>
 	</array>
 	<key>UILaunchStoryboardName</key>
-	<string>LaunchScreen.storyboard</string>
+	<string>LaunchScreen</string>
 	<key>LSApplicationQueriesSchemes</key>
 	<array>
 		<string>googledrive</string>
diff --git a/ios/chrome/app/resources/LaunchScreen.storyboard b/ios/chrome/app/resources/LaunchScreen.storyboard
deleted file mode 100644
index 2e3ff5e..0000000
--- a/ios/chrome/app/resources/LaunchScreen.storyboard
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24112" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX">
-    <device id="ipad11_0rounded" orientation="portrait" layout="fullscreen" appearance="light"/>
-    <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24057"/>
-        <capability name="Named colors" minToolsVersion="9.0"/>
-        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="s0d-6b-0kx">
-            <objects>
-                <viewController id="Y6W-OH-hqX" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="5EZ-qb-Rvc">
-                        <rect key="frame" x="0.0" y="0.0" width="834" height="1210"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <subviews>
-                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launchscreen_app_logo" translatesAutoresizingMaskIntoConstraints="NO" id="rWR-eH-agn">
-                                <rect key="frame" x="321" y="509" width="192" height="192"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" priority="999" constant="192" id="2VT-cj-wAc"/>
-                                    <constraint firstAttribute="width" secondItem="rWR-eH-agn" secondAttribute="height" multiplier="1:1" id="D4M-BF-UXC"/>
-                                </constraints>
-                            </imageView>
-                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" image="launchscreen_brand_name" translatesAutoresizingMaskIntoConstraints="NO" id="oyn-9t-6PW">
-                                <rect key="frame" x="363.5" y="1110" width="107" height="35"/>
-                                <constraints>
-                                    <constraint firstAttribute="width" constant="107" id="HGy-cC-r6n"/>
-                                    <constraint firstAttribute="height" constant="35" id="iau-bb-CIU"/>
-                                </constraints>
-                            </imageView>
-                        </subviews>
-                        <viewLayoutGuide key="safeArea" id="vDu-zF-Fre"/>
-                        <color key="backgroundColor" name="background_color"/>
-                        <constraints>
-                            <constraint firstItem="rWR-eH-agn" firstAttribute="centerY" secondItem="5EZ-qb-Rvc" secondAttribute="centerY" id="9Ws-8o-3mX"/>
-                            <constraint firstItem="rWR-eH-agn" firstAttribute="height" relation="lessThanOrEqual" secondItem="5EZ-qb-Rvc" secondAttribute="height" multiplier="0.381966" id="LNE-wR-pws"/>
-                            <constraint firstItem="rWR-eH-agn" firstAttribute="width" relation="lessThanOrEqual" secondItem="5EZ-qb-Rvc" secondAttribute="width" multiplier="0.381966" id="N0s-Jp-t8J"/>
-                            <constraint firstItem="vDu-zF-Fre" firstAttribute="bottom" secondItem="oyn-9t-6PW" secondAttribute="bottom" constant="20" id="bmW-Bx-pkF"/>
-                            <constraint firstItem="oyn-9t-6PW" firstAttribute="centerX" secondItem="5EZ-qb-Rvc" secondAttribute="centerX" id="dhU-1U-mKZ"/>
-                            <constraint firstItem="rWR-eH-agn" firstAttribute="centerX" secondItem="5EZ-qb-Rvc" secondAttribute="centerX" id="jmD-ME-FSI"/>
-                        </constraints>
-                    </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="Ief-a0-LHa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="139" y="131"/>
-        </scene>
-    </scenes>
-    <resources>
-        <image name="launchscreen_app_logo" width="192" height="192"/>
-        <image name="launchscreen_brand_name" width="107" height="35"/>
-        <namedColor name="background_color">
-            <color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
-        </namedColor>
-    </resources>
-</document>
diff --git a/ios/chrome/app/resources/LaunchScreen.xib b/ios/chrome/app/resources/LaunchScreen.xib
new file mode 100644
index 0000000..e7beae23
--- /dev/null
+++ b/ios/chrome/app/resources/LaunchScreen.xib
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
+        <capability name="Named colors" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <viewController id="Ssz-5V-cv2">
+            <layoutGuides>
+                <viewControllerLayoutGuide type="top" id="cfQ-4H-yja"/>
+                <viewControllerLayoutGuide type="bottom" id="TrJ-rv-PCn"/>
+            </layoutGuides>
+            <view key="view" contentMode="scaleToFill" id="tRS-Cx-RH3">
+                <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                <subviews>
+                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launchscreen_app_logo" translatesAutoresizingMaskIntoConstraints="NO" id="K7H-Iv-QNk">
+                        <rect key="frame" x="128" y="369" width="158" height="158"/>
+                        <constraints>
+                            <constraint firstAttribute="width" relation="lessThanOrEqual" constant="192" id="Ybu-iB-Ad4"/>
+                            <constraint firstAttribute="height" relation="lessThanOrEqual" constant="192" id="gGV-z8-zNx"/>
+                            <constraint firstAttribute="width" secondItem="K7H-Iv-QNk" secondAttribute="height" multiplier="1:1" id="ion-RZ-6NS"/>
+                        </constraints>
+                    </imageView>
+                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launchscreen_brand_name" translatesAutoresizingMaskIntoConstraints="NO" id="bAU-qs-X5w">
+                        <rect key="frame" x="153.5" y="807" width="107" height="35"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="107" id="0Mf-i7-mvo"/>
+                            <constraint firstAttribute="height" constant="35" id="7Gs-G7-OR2"/>
+                        </constraints>
+                    </imageView>
+                </subviews>
+                <color key="backgroundColor" name="background_color"/>
+                <constraints>
+                    <constraint firstItem="K7H-Iv-QNk" firstAttribute="width" secondItem="tRS-Cx-RH3" secondAttribute="width" multiplier="0.381966" id="3hJ-Yo-1Tg"/>
+                    <constraint firstItem="K7H-Iv-QNk" firstAttribute="height" secondItem="tRS-Cx-RH3" secondAttribute="height" multiplier="0.381966" id="962-tL-cOd"/>
+                    <constraint firstItem="K7H-Iv-QNk" firstAttribute="centerY" secondItem="tRS-Cx-RH3" secondAttribute="centerY" id="N7G-n6-9nU">
+                        <variation key="heightClass=compact" constant="-10"/>
+                    </constraint>
+                    <constraint firstItem="K7H-Iv-QNk" firstAttribute="centerX" secondItem="tRS-Cx-RH3" secondAttribute="centerX" id="V5t-fF-KbQ"/>
+                    <constraint firstItem="bAU-qs-X5w" firstAttribute="centerX" secondItem="K7H-Iv-QNk" secondAttribute="centerX" id="f8n-OV-luE"/>
+                    <constraint firstAttribute="bottomMargin" secondItem="bAU-qs-X5w" secondAttribute="bottom" constant="20" id="p2z-ft-dzH"/>
+                </constraints>
+                <variation key="default">
+                    <mask key="constraints">
+                        <exclude reference="3hJ-Yo-1Tg"/>
+                        <exclude reference="962-tL-cOd"/>
+                    </mask>
+                </variation>
+                <variation key="heightClass=compact">
+                    <mask key="constraints">
+                        <include reference="962-tL-cOd"/>
+                    </mask>
+                </variation>
+                <variation key="heightClass=regular-widthClass=compact">
+                    <mask key="constraints">
+                        <include reference="3hJ-Yo-1Tg"/>
+                    </mask>
+                </variation>
+            </view>
+            <point key="canvasLocation" x="548" y="1086"/>
+        </viewController>
+    </objects>
+    <resources>
+        <image name="launchscreen_app_logo" width="192" height="192"/>
+        <image name="launchscreen_brand_name" width="107" height="35"/>
+        <namedColor name="background_color">
+            <color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </namedColor>
+    </resources>
+</document>
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 3a22a49..0f5a6a2 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -6298,15 +6298,6 @@
       <message name="IDS_IOS_SHARE_KIT_BLOCK_MESSAGE" desc="The message shown when the user tries to block another user.">
         <ph name="USER_NAME">$1<ex>John Doe</ex></ph> (<ph name="USER_EMAIL">$2<ex>john.doe@gmail.com</ex></ph>) will immediately lose access to the “<ph name="GROUP_NAME">$3<ex>Vacation</ex></ph>" tab group, and will no longer be able to interact with you across Google services
       </message>
-      <message name="IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_ACTION_TITLE" desc="The title of the button in the alert displayed when the shared link has expired.">
-        Got it
-      </message>
-      <message name="IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_MESSAGE" desc="The message in the alert displayed when the shared link has expired.">
-        Contact the sender to ask for a new link
-      </message>
-      <message name="IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_TITLE" desc="The title of the alert displayed when the shared link has expired.">
-        This link doesn’t work
-      </message>
       <message name="IDS_IOS_SHARE_KIT_JOIN_DISCLAIMER_CAPTION" desc="The caption part of the disclaimer for sharing a tab group.">
         <ph name="USER_NAME">$1<ex>John Doe</ex></ph> (<ph name="USER_EMAIL">$2<ex>john.doe@gmail.com</ex></ph>) wants you to join a tab group. Anyone with the link can edit all tabs, so join with care. Link expires in 48 hr.
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_ACTION_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_ACTION_TITLE.png.sha1
deleted file mode 100644
index e27da285..0000000
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_ACTION_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-de533cacadb20bdf3a47544c170cb22eaed0d74f
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_MESSAGE.png.sha1
deleted file mode 100644
index e27da285..0000000
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-de533cacadb20bdf3a47544c170cb22eaed0d74f
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_TITLE.png.sha1
deleted file mode 100644
index e27da285..0000000
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-de533cacadb20bdf3a47544c170cb22eaed0d74f
\ No newline at end of file
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 1c1d7c1..3434a39 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -130,6 +130,7 @@
   "+components/unified_consent",
   "+components/update_client",
   "+components/upload_list",
+  "+components/user_data_importer",
   "+components/url_formatter",
   "+components/variations",
   "+components/variations/net",
diff --git a/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm b/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm
index b3718c8..81b174dd 100644
--- a/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm
@@ -450,6 +450,11 @@
 // Tests that tapping on an account button causes the managed account to sign
 // out with a sign-out confirmation dialog.
 - (void)testSwitchFromManagedAccount {
+  // TODO(crbug.com/433726717): Test disabled on iPhones.
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
+  }
+
   [SigninEarlGrey
       signinWithFakeManagedIdentityInPersonalProfile:kManagedIdentity1];
   [ChromeEarlGreyUI waitForAppToIdle];
@@ -477,6 +482,11 @@
 // to be changed and the account menu view to be closed after showing managed
 // account sign-in dialog.
 - (void)testSwitchToManagedAccount {
+  // TODO(crbug.com/433726717): Test disabled on iPhones.
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
+  }
+
   [SigninEarlGrey signinWithFakeIdentity:kPrimaryIdentity];
   [SigninEarlGrey addFakeIdentity:kManagedIdentity1];
   [self selectIdentityDisc];
@@ -509,6 +519,11 @@
 }
 
 - (void)testSwitchFromManagedAccountToManagedAccount {
+  // TODO(crbug.com/433726717): Test disabled on iPhones.
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
+  }
+
   [SigninEarlGrey
       signinWithFakeManagedIdentityInPersonalProfile:kManagedIdentity1];
   [ChromeEarlGreyUI waitForAppToIdle];
@@ -556,6 +571,11 @@
 // Verifies identity confirmation snackbar shows on startup with multiple
 // identities on device after 1 day.
 - (void)testMultipleIdentities_IdentityConfirmationToast {
+  // TODO(crbug.com/433726717): Test disabled on iPhones.
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
+  }
+
   [self prepareStartSurface];
   // Add multiple identities and sign in with one of them.
   [SigninEarlGrey signinWithFakeIdentity:kPrimaryIdentity];
@@ -615,6 +635,11 @@
 // Verifies identity confirmation snackbar shows on startup with multiple
 // identities on device with frequency limitations.
 - (void)testFrequencyLimitation_IdentityConfirmationToast {
+  // TODO(crbug.com/433726717): Test disabled on iPhones.
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
+  }
+
   [self prepareStartSurface];
   // Add multiple identities and sign in with one of them.
   [SigninEarlGrey signinWithFakeIdentity:kPrimaryIdentity];
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/signin/BUILD.gn
index 47c5201..0a0548b 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/BUILD.gn
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/BUILD.gn
@@ -22,6 +22,7 @@
     "//components/signin/public/base",
     "//components/signin/public/identity_manager",
     "//components/sync/base",
+    "//ios/chrome/app:change_profile_continuation",
     "//ios/chrome/browser/authentication/ui_bundled:continuation",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator:animated_coordinator",
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h b/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h
index c8a30cf..8454733 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h
@@ -11,11 +11,13 @@
 #import "base/ios/block_types.h"
 #import "components/signin/public/identity_manager/tribool.h"
 #import "components/sync/base/data_type.h"
+#import "ios/chrome/app/change_profile_continuation.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_constants.h"
 #import "ios/chrome/browser/signin/model/capabilities_types.h"
 #import "ios/chrome/browser/signin/model/system_identity.h"
 
 class Browser;
+enum class ChangeProfileReason;
 class ChromeAccountManagerService;
 @class MDCSnackbarMessage;
 class ProfileIOS;
@@ -155,6 +157,12 @@
     syncer::SyncService* sync_service,
     UnsyncedDataForSignoutOrProfileSwitchingCallback callback);
 
+// Post an asynchronous request to switch from a managed profile to the
+// personal profile, running `continuation` when the change completes.
+void SwitchToPersonalProfile(SceneState* scene_state,
+                             ChangeProfileReason reason,
+                             ChangeProfileContinuation continuation);
+
 }  // namespace signin
 
 #endif  // IOS_CHROME_BROWSER_AUTHENTICATION_UI_BUNDLED_SIGNIN_SIGNIN_UTILS_H_
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.mm b/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.mm
index 4acd8bf..b2c9ad4 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.mm
@@ -155,21 +155,6 @@
                      weak_scene_state, reason, std::move(continuation)));
 }
 
-// Post an asynchronous request to switch from a managed profile to the
-// personal profile, running `continuation` when the change completes.
-void SwitchToPersonalProfile(SceneState* scene_state,
-                             ChangeProfileReason reason,
-                             ChangeProfileContinuation continuation) {
-  ProfileManagerIOS* profile_manager =
-      GetApplicationContext()->GetProfileManager();
-  std::string personal_profile_name =
-      profile_manager->GetProfileAttributesStorage()->GetPersonalProfileName();
-  CHECK(profile_manager->HasProfileWithName(personal_profile_name));
-
-  SwitchToProfile(scene_state, personal_profile_name, reason,
-                  std::move(continuation));
-}
-
 syncer::DataTypeSet DataCountsMapToDataTypeSet(
     absl::flat_hash_map<syncer::DataType, size_t> type_counts) {
   syncer::DataTypeSet types;
@@ -570,4 +555,19 @@
       base::BindOnce(&DataCountsMapToDataTypeSet).Then(std::move(callback)));
 }
 
+// Post an asynchronous request to switch from a managed profile to the
+// personal profile, running `continuation` when the change completes.
+void SwitchToPersonalProfile(SceneState* scene_state,
+                             ChangeProfileReason reason,
+                             ChangeProfileContinuation continuation) {
+  ProfileManagerIOS* profile_manager =
+      GetApplicationContext()->GetProfileManager();
+  std::string personal_profile_name =
+      profile_manager->GetProfileAttributesStorage()->GetPersonalProfileName();
+  CHECK(profile_manager->HasProfileWithName(personal_profile_name));
+
+  SwitchToProfile(scene_state, personal_profile_name, reason,
+                  std::move(continuation));
+}
+
 }  // namespace signin
diff --git a/ios/chrome/browser/bookmarks/ui_bundled/home/bookmark_promo_controller.mm b/ios/chrome/browser/bookmarks/ui_bundled/home/bookmark_promo_controller.mm
index cd2b9aa..fea588e 100644
--- a/ios/chrome/browser/bookmarks/ui_bundled/home/bookmark_promo_controller.mm
+++ b/ios/chrome/browser/bookmarks/ui_bundled/home/bookmark_promo_controller.mm
@@ -23,11 +23,13 @@
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/signin/model/authentication_service_factory.h"
+#import "ios/chrome/browser/signin/model/authentication_service_observer_bridge.h"
 #import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/signin/model/identity_manager_factory.h"
 #import "ios/chrome/browser/sync/model/sync_service_factory.h"
 
-@interface BookmarkPromoController () <IdentityManagerObserverBridgeDelegate,
+@interface BookmarkPromoController () <AuthenticationServiceObserving,
+                                       IdentityManagerObserverBridgeDelegate,
                                        SigninPromoViewConsumer>
 
 @end
@@ -38,6 +40,11 @@
       _identityManagerObserverBridge;
   // Mediator to use for the sign-in promo view displayed in the bookmark view.
   SigninPromoViewMediator* _signinPromoViewMediator;
+  // Authentication Service to retrieve the user's signed-in state.
+  raw_ptr<AuthenticationService> _authService;
+  // Observer for auth service status changes.
+  std::unique_ptr<AuthenticationServiceObserverBridge>
+      _authServiceObserverBridge;
 }
 
 - (instancetype)initWithBrowser:(Browser*)browser
@@ -75,6 +82,10 @@
           return CreateChangeProfileBookmarksContinuation();
         })];
     _signinPromoViewMediator.consumer = self;
+    _authService = AuthenticationServiceFactory::GetForProfile(profile);
+    _authServiceObserverBridge =
+        std::make_unique<AuthenticationServiceObserverBridge>(_authService,
+                                                              self);
     _signinPromoViewMediator.dataTypeToWaitForInitialSync =
         syncer::DataType::BOOKMARKS;
     [self updateShouldShowSigninPromo];
@@ -153,6 +164,12 @@
   return _signinPromoViewMediator.signinInProgress;
 }
 
+#pragma mark - AuthenticationServiceObserving
+
+- (void)onServiceStatusChanged {
+  [self updateShouldShowSigninPromo];
+}
+
 #pragma mark - IdentityManagerObserverBridgeDelegate
 
 // Called when a user changes the syncing state.
diff --git a/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn b/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
index 6c7d580..7e9bed98 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/browser_view/ui_bundled/BUILD.gn
@@ -95,7 +95,7 @@
     "//ios/chrome/browser/content_suggestions/ui_bundled:coordinator",
     "//ios/chrome/browser/context_menu/ui_bundled:coordinator",
     "//ios/chrome/browser/contextual_panel/coordinator",
-    "//ios/chrome/browser/contextual_panel/model",
+    "//ios/chrome/browser/contextual_panel/model:public",
     "//ios/chrome/browser/contextual_panel/utils",
     "//ios/chrome/browser/crash_report/model",
     "//ios/chrome/browser/credential_provider_promo/ui_bundled:coordinator",
diff --git a/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller.mm b/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller.mm
index 8bd94c3..951afeaf 100644
--- a/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller.mm
+++ b/ios/chrome/browser/browser_view/ui_bundled/browser_view_controller.mm
@@ -1142,10 +1142,12 @@
 
       // Load view from Launch Screen and add it to window.
       NSBundle* mainBundle = base::apple::FrameworkBundle();
-      UIStoryboard* storyboard =
-          [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:mainBundle];
+      NSArray* topObjects = [mainBundle loadNibNamed:@"LaunchScreen"
+                                               owner:self
+                                             options:nil];
       UIViewController* launchScreenController =
-          [storyboard instantiateInitialViewController];
+          base::apple::ObjCCastStrict<UIViewController>(
+              [topObjects lastObject]);
       // `launchScreenView` is loaded as an autoreleased object, and is retained
       // by the `completion` block below.
       UIView* launchScreenView = launchScreenController.view;
diff --git a/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client.mm b/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client.mm
index 514907ac..34b2ba74 100644
--- a/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client.mm
+++ b/ios/chrome/browser/commerce/model/push_notification/commerce_push_notification_client.mm
@@ -58,7 +58,12 @@
 ProfileIOS* GetAnyProfile() {
   std::vector<ProfileIOS*> loaded_profiles =
       GetApplicationContext()->GetProfileManager()->GetLoadedProfiles();
-  CHECK(!loaded_profiles.empty());
+
+  // Even if there is only one Profile on disk, it may have not been loaded yet.
+  if (loaded_profiles.empty()) {
+    return nullptr;
+  }
+
   return loaded_profiles.back();
 }
 
@@ -128,21 +133,43 @@
 std::optional<UIBackgroundFetchResult>
 CommercePushNotificationClient::HandleNotificationReception(
     NSDictionary<NSString*, id>* notification) {
+  ProfileIOS* profile = GetTargetProfile();
+
+  if (!profile) {
+    // Cannot process the notification without a Profile.
+    return std::nullopt;
+  }
+
   OptimizationGuideService* optimization_guide_service =
-      OptimizationGuideServiceFactory::GetForProfile(GetTargetProfile());
+      OptimizationGuideServiceFactory::GetForProfile(profile);
+
+  if (!optimization_guide_service ||
+      !optimization_guide_service->GetHintsManager()) {
+    return std::nullopt;
+  }
+
   std::unique_ptr<optimization_guide::proto::HintNotificationPayload>
       hint_notification_payload = ParseHintNotificationPayload(
           [notification objectForKey:kSerializedPayloadKey]);
+
   if (hint_notification_payload) {
     base::RecordAction(base::UserMetricsAction(
         "Commerce.PriceTracking.PushNotification.Received"));
+
     optimization_guide::PushNotificationManager* push_notification_manager =
         optimization_guide_service->GetHintsManager()
             ->push_notification_manager();
+
+    if (!push_notification_manager) {
+      return std::nullopt;
+    }
+
     push_notification_manager->OnNewPushNotification(
         *hint_notification_payload);
+
     return UIBackgroundFetchResultNoData;
   }
+
   return std::nullopt;
 }
 
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/cells/content_suggestions_tile_saver.mm b/ios/chrome/browser/content_suggestions/ui_bundled/cells/content_suggestions_tile_saver.mm
index 2f555ad..9cc90304 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/cells/content_suggestions_tile_saver.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/cells/content_suggestions_tile_saver.mm
@@ -260,13 +260,18 @@
                                         ->GetPersonalProfileName();
 
   if (profileName == personalProfileName) {
-    // If we are in personal profile, data is saved also to "Default". This will
-    // be used to retrieve data for a widget with no signed-in account.
-    [suggested_items setObject:data forKey:app_group::kDefaultAccount];
+    // If we are in personal profile, data is saved also to "No account". This
+    // will be used to retrieve data for a widget with no signed-in account.
+    [suggested_items setObject:data forKey:app_group::kNoAccount];
     [last_modification_dates setObject:last_modification_date
-                                forKey:app_group::kDefaultAccount];
+                                forKey:app_group::kNoAccount];
   }
 
+  // Always update last modification date for "Default" scenario.
+  [suggested_items setObject:data forKey:app_group::kDefault];
+  [last_modification_dates setObject:last_modification_date
+                              forKey:app_group::kDefault];
+
   // Update stored info for all identities in the current profile.
   for (id<SystemIdentity> identity in account_manager_service
            ->GetAllIdentities()) {
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/BUILD.gn b/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/BUILD.gn
index be8edfc..b26185fb 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/BUILD.gn
@@ -13,7 +13,10 @@
     "use_autofill_instructional_view_controller.h",
     "use_autofill_instructional_view_controller.mm",
   ]
-  public_deps = [ "//ios/chrome/browser/tips_notifications/ui:shared" ]
+  public_deps = [
+    "//ios/chrome/browser/shared/ui/animated_promo",
+    "//ios/chrome/browser/tips_notifications/ui:shared",
+  ]
   deps = [
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/resources",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/save_passwords_instructional_view_controller.h b/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/save_passwords_instructional_view_controller.h
index 0a8d9d0..66fb8cb 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/save_passwords_instructional_view_controller.h
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/save_passwords_instructional_view_controller.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_TIPS_UI_SAVE_PASSWORDS_INSTRUCTIONAL_VIEW_CONTROLLER_H_
 #define IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_TIPS_UI_SAVE_PASSWORDS_INSTRUCTIONAL_VIEW_CONTROLLER_H_
 
-#import "ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h"
+#import "ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h"
 
 // The view controller for the full-screen, animated Save Passwords
 // instructional tip.
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/use_autofill_instructional_view_controller.h b/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/use_autofill_instructional_view_controller.h
index 5d6a1c9..26c8f3e 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/use_autofill_instructional_view_controller.h
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/tips/ui/use_autofill_instructional_view_controller.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_TIPS_UI_USE_AUTOFILL_INSTRUCTIONAL_VIEW_CONTROLLER_H_
 #define IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_TIPS_UI_USE_AUTOFILL_INSTRUCTIONAL_VIEW_CONTROLLER_H_
 
-#import "ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h"
+#import "ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h"
 
 // The view controller for the full-screen, animated Use Autofill instructional
 // tip.
diff --git a/ios/chrome/browser/contextual_panel/entrypoint/coordinator/contextual_panel_entrypoint_mediator.mm b/ios/chrome/browser/contextual_panel/entrypoint/coordinator/contextual_panel_entrypoint_mediator.mm
index d010ecb..99b9ff7a 100644
--- a/ios/chrome/browser/contextual_panel/entrypoint/coordinator/contextual_panel_entrypoint_mediator.mm
+++ b/ios/chrome/browser/contextual_panel/entrypoint/coordinator/contextual_panel_entrypoint_mediator.mm
@@ -183,6 +183,21 @@
                                                   centered:centered];
 }
 
+- (void)didCompleteTransitionToSmallEntrypoint {
+  web::WebState* activeWebState = _webStateList->GetActiveWebState();
+  if (!activeWebState || activeWebState->IsBeingDestroyed()) {
+    return;
+  }
+  // Notify the configuration item that it transitioned to a small entrypoint.
+  ContextualPanelTabHelper* contextualPanelTabHelper =
+      ContextualPanelTabHelper::FromWebState(activeWebState);
+  ContextualPanelItemConfiguration* config =
+      contextualPanelTabHelper->GetFirstCachedConfig().get();
+  if (config) {
+    config->DidTransitionToSmallEntrypoint();
+  }
+}
+
 #pragma mark - ContextualPanelTabHelperObserving
 
 - (void)contextualPanel:(ContextualPanelTabHelper*)tabHelper
diff --git a/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_mutator.h b/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_mutator.h
index c624897..7830580 100644
--- a/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_mutator.h
+++ b/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_mutator.h
@@ -19,6 +19,9 @@
 // "absolute" center.
 - (void)setLocationBarLabelCenteredBetweenContent:(BOOL)centered;
 
+// Notify the mutator that the transition to a small entrypoint was completed.
+- (void)didCompleteTransitionToSmallEntrypoint;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_CONTEXTUAL_PANEL_ENTRYPOINT_UI_CONTEXTUAL_PANEL_ENTRYPOINT_MUTATOR_H_
diff --git a/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_view_controller.mm b/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_view_controller.mm
index 4dbe80b..e9ee2b3 100644
--- a/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_view_controller.mm
+++ b/ios/chrome/browser/contextual_panel/entrypoint/ui/contextual_panel_entrypoint_view_controller.mm
@@ -384,6 +384,13 @@
       UIContentSizeCategoryAccessibilityLarge);
 }
 
+// Refreshes the VoiceOver bounding box and notifies the mutator that the
+// animation to transition to a small entrypoint has completed.
+- (void)didCompleteTransitionToSmallEntrypoint {
+  [self refreshVoiceOverBoundingBoxIfFocused];
+  [self.mutator didCompleteTransitionToSmallEntrypoint];
+}
+
 // Sets the proper entrypoint visual features depending on current infobar
 // badges status and whether the Contextual Panel is open.
 - (void)refreshEntrypointVisualElements {
@@ -598,7 +605,7 @@
                                UIViewAnimationOptionAllowUserInteraction)
                    animations:animateTransitionToSmallEntrypoint
                    completion:^(BOOL completed) {
-                     [weakSelf refreshVoiceOverBoundingBoxIfFocused];
+                     [weakSelf didCompleteTransitionToSmallEntrypoint];
                    }];
 
   [_entrypointContainer removeGestureRecognizer:_swipeRecognizer];
diff --git a/ios/chrome/browser/contextual_panel/model/BUILD.gn b/ios/chrome/browser/contextual_panel/model/BUILD.gn
index 56683d5..767294c 100644
--- a/ios/chrome/browser/contextual_panel/model/BUILD.gn
+++ b/ios/chrome/browser/contextual_panel/model/BUILD.gn
@@ -9,7 +9,6 @@
     "contextual_panel_model_service.mm",
     "contextual_panel_model_service_factory.h",
     "contextual_panel_model_service_factory.mm",
-    "contextual_panel_tab_helper.h",
     "contextual_panel_tab_helper.mm",
   ]
   deps = [
@@ -40,6 +39,7 @@
     "contextual_panel_item_type.h",
     "contextual_panel_item_type.mm",
     "contextual_panel_model.h",
+    "contextual_panel_tab_helper.h",
     "contextual_panel_tab_helper_observer.h",
     "contextual_panel_tab_helper_observer_bridge.h",
     "contextual_panel_tab_helper_observer_bridge.mm",
@@ -49,6 +49,7 @@
     "//base",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/public/features",
+    "//ios/web/public",
   ]
 }
 
diff --git a/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.h b/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.h
index eaac330..15378c4a 100644
--- a/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.h
+++ b/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.h
@@ -23,7 +23,7 @@
   static const int low_relevance;
 
   explicit ContextualPanelItemConfiguration(ContextualPanelItemType item_type);
-  ~ContextualPanelItemConfiguration();
+  virtual ~ContextualPanelItemConfiguration();
   ContextualPanelItemConfiguration(
       const ContextualPanelItemConfiguration& other) = delete;
   ContextualPanelItemConfiguration& operator=(
@@ -37,6 +37,10 @@
   // Returns the duration of the large entrypoint for this item.
   base::TimeDelta GetLargeEntrypointDisplayedDuration();
 
+  // Notify the configuration that it transitioned to a small entrypoint so it
+  // can react accordingly depending on the type of configuration.
+  virtual void DidTransitionToSmallEntrypoint();
+
   // The different supported image types.
   enum class EntrypointImageType {
     // The image name is a UIImage to be loaded in.
diff --git a/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.mm b/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.mm
index bb0d61c..cb05dd9 100644
--- a/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.mm
+++ b/ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.mm
@@ -37,3 +37,7 @@
   }
   return base::Seconds(LargeContextualPanelEntrypointDisplayedInSeconds());
 }
+
+void ContextualPanelItemConfiguration::DidTransitionToSmallEntrypoint() {
+  // No-op by default.
+}
diff --git a/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.h b/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.h
index 2fbc186..288a040 100644
--- a/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.h
+++ b/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.h
@@ -96,6 +96,10 @@
   void WasShown(web::WebState* web_state) override;
   void WasHidden(web::WebState* web_state) override;
 
+  // Invalidates the provided `configuration` from the cached list.
+  void InvalidateContextualPanelItemConfiguration(
+      ContextualPanelItemConfiguration* configuration);
+
  protected:
   // Protected to allow test overriding.
   ContextualPanelTabHelper(
@@ -131,6 +135,9 @@
   // Query all the individual models for their data.
   void QueryModels();
 
+  // Updates item configurations to match model responses.
+  void UpdateItemConfigurations();
+
   // Do any necessary work after all requests are completed or time out.
   void AllRequestsFinished();
 
diff --git a/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.mm b/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.mm
index 1f78cc9..3f9a3aae7 100644
--- a/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.mm
+++ b/ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.mm
@@ -180,6 +180,27 @@
   }
 }
 
+#pragma mark - ContextualPanelItemConfiguration::Delegate
+
+void ContextualPanelTabHelper::InvalidateContextualPanelItemConfiguration(
+    ContextualPanelItemConfiguration* configuration) {
+  // Reset `configuration` if found in `responses_` and check whether all
+  // responses have been completed.
+  bool all_responses_completed = true;
+  bool config_found = false;
+  for (auto& [key, response] : responses_) {
+    all_responses_completed = all_responses_completed && response.completed;
+    if (key == configuration->item_type &&
+        response.configuration.get() == configuration) {
+      response.configuration.reset();
+      config_found = true;
+    }
+  }
+  if (config_found && all_responses_completed) {
+    UpdateItemConfigurations();
+  }
+}
+
 #pragma mark - Private
 
 void ContextualPanelTabHelper::QueryModels() {
@@ -233,7 +254,7 @@
   AllRequestsFinished();
 }
 
-void ContextualPanelTabHelper::AllRequestsFinished() {
+void ContextualPanelTabHelper::UpdateItemConfigurations() {
   sorted_weak_configurations_.clear();
 
   // The active configurations passed to observers as weak ptrs.
@@ -265,7 +286,10 @@
   for (auto& observer : observers_) {
     observer.ContextualPanelHasNewData(this, sorted_weak_configurations_);
   }
+}
 
+void ContextualPanelTabHelper::AllRequestsFinished() {
+  UpdateItemConfigurations();
   FireRequestsFinishedMetrics();
 }
 
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service.h b/ios/chrome/browser/credential_provider/model/credential_provider_service.h
index ef75b65..c7990ee0 100644
--- a/ios/chrome/browser/credential_provider/model/credential_provider_service.h
+++ b/ios/chrome/browser/credential_provider/model/credential_provider_service.h
@@ -147,6 +147,9 @@
   // Syncs whether or not PRF is enabled.
   void UpdatePasskeyPRFSetting();
 
+  // Syncs whether or not signal API is enabled.
+  void UpdateSignalAPISetting();
+
   // PasswordStoreConsumer:
   void OnGetPasswordStoreResultsOrErrorFrom(
       password_manager::PasswordStoreInterface* store,
@@ -186,9 +189,6 @@
   // The name of the profile used to create this CredentialProviderService.
   const std::string profile_name_;
 
-  // The pref service.
-  const raw_ptr<PrefService> prefs_;
-
   // The local state. Used to query the last used profile.
   const raw_ptr<PrefService> local_state_;
 
diff --git a/ios/chrome/browser/credential_provider/model/credential_provider_service.mm b/ios/chrome/browser/credential_provider/model/credential_provider_service.mm
index 6b480a9..4fdf136 100644
--- a/ios/chrome/browser/credential_provider/model/credential_provider_service.mm
+++ b/ios/chrome/browser/credential_provider/model/credential_provider_service.mm
@@ -167,7 +167,6 @@
     affiliations::AffiliationService* affiliation_service,
     FaviconLoader* favicon_loader)
     : profile_name_(profile_name),
-      prefs_(prefs),
       local_state_(local_state),
       profile_password_store_(profile_password_store),
       account_password_store_(account_password_store),
@@ -234,6 +233,7 @@
   UpdatePasswordSyncSetting();
   UpdateAutomaticPasskeyUpgradeSetting();
   UpdatePasskeyPRFSetting();
+  UpdateSignalAPISetting();
 }
 
 CredentialProviderService::~CredentialProviderService() {}
@@ -565,7 +565,7 @@
   }
 
   std::optional accountForSaving =
-      password_manager::sync_util::GetAccountForSaving(prefs_, sync_service_);
+      password_manager::sync_util::GetAccountForSaving(sync_service_);
   [app_group::GetGroupUserDefaults()
       setObject:accountForSaving ? base::SysUTF8ToNSString(*accountForSaving)
                                  : nil
@@ -611,6 +611,17 @@
          forKey:AppGroupUserDefaulsCredentialProviderPasskeyPRFEnabled()];
 }
 
+void CredentialProviderService::UpdateSignalAPISetting() {
+  if (!IsLastUsedProfile()) {
+    return;
+  }
+
+  BOOL is_enabled = base::FeatureList::IsEnabled(kCredentialProviderSignalAPI);
+  [app_group::GetGroupUserDefaults()
+      setObject:[NSNumber numberWithBool:is_enabled]
+         forKey:AppGroupUserDefaulsCredentialProviderSignalAPIEnabled()];
+}
+
 void CredentialProviderService::OnGetPasswordStoreResultsOrErrorFrom(
     password_manager::PasswordStoreInterface* store,
     password_manager::LoginsResultOrError results) {
diff --git a/ios/chrome/browser/credential_provider/model/features.h b/ios/chrome/browser/credential_provider/model/features.h
index d95d23b..b95d90f 100644
--- a/ios/chrome/browser/credential_provider/model/features.h
+++ b/ios/chrome/browser/credential_provider/model/features.h
@@ -18,6 +18,9 @@
 // provider.
 BASE_DECLARE_FEATURE(kCredentialProviderPerformanceImprovements);
 
+// Feature flag to enable signal API in the credential provider.
+BASE_DECLARE_FEATURE(kCredentialProviderSignalAPI);
+
 // Returns whether the CPE Performance Improvement Feature is enabled.
 bool IsCPEPerformanceImprovementsEnabled();
 
diff --git a/ios/chrome/browser/credential_provider/model/features.mm b/ios/chrome/browser/credential_provider/model/features.mm
index 4070a9b5..872d2ea 100644
--- a/ios/chrome/browser/credential_provider/model/features.mm
+++ b/ios/chrome/browser/credential_provider/model/features.mm
@@ -16,6 +16,10 @@
              "CredentialProviderPerformanceImprovements",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kCredentialProviderSignalAPI,
+             "CredentialProviderSignalAPI",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 bool IsCPEPerformanceImprovementsEnabled() {
   return base::FeatureList::IsEnabled(
       kCredentialProviderPerformanceImprovements);
diff --git a/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_view_controller.h b/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_view_controller.h
index 15a277eb..6f949af 100644
--- a/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_view_controller.h
+++ b/ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_view_controller.h
@@ -12,6 +12,7 @@
 
 // Container view controller for the Credential Provider Extension promo. Can be
 // configured to display the half-sheet or full-screen promo.
+// TODO(crbug.com/433794412): Subclass from AnimatedPromoViewController.
 @interface CredentialProviderPromoViewController
     : UIViewController <CredentialProviderPromoConsumer>
 
diff --git a/ios/chrome/browser/default_promo/ui_bundled/default_browser_instructions_view_controller.h b/ios/chrome/browser/default_promo/ui_bundled/default_browser_instructions_view_controller.h
index 21d76f9..453668a 100644
--- a/ios/chrome/browser/default_promo/ui_bundled/default_browser_instructions_view_controller.h
+++ b/ios/chrome/browser/default_promo/ui_bundled/default_browser_instructions_view_controller.h
@@ -18,6 +18,7 @@
 extern NSString* const kDefaultBrowserInstructionsViewDarkAnimationViewId;
 
 // View for the displaying default browser instructions.
+// TODO(crbug.com/433786239): Subclass from AnimatedPromoViewController.
 @interface DefaultBrowserInstructionsViewController : UIViewController
 
 // Creates the view with specified `titleText` based on provided parameters.
diff --git a/ios/chrome/browser/default_promo/ui_bundled/post_restore/post_restore_default_browser_egtest.mm b/ios/chrome/browser/default_promo/ui_bundled/post_restore/post_restore_default_browser_egtest.mm
index 2f81f32e..c6ef48fc 100644
--- a/ios/chrome/browser/default_promo/ui_bundled/post_restore/post_restore_default_browser_egtest.mm
+++ b/ios/chrome/browser/default_promo/ui_bundled/post_restore/post_restore_default_browser_egtest.mm
@@ -92,12 +92,11 @@
 // browser before a restore. Verifies that secondary action button dismisses the
 // promo.
 - (void)testPromoAppears {
-  // TODO(crbug.com/418750327): Test fails on ipad device.
-#if !TARGET_OS_SIMULATOR
+  // TODO(crbug.com/418750327): Test fails on ipad device/simulator.
   if ([ChromeEarlGrey isIPadIdiom]) {
     EARL_GREY_TEST_DISABLED(@"Fails on iPad.");
   }
-#endif
+
   // Simulate setting Chrome as default browser.
   NSMutableDictionary<NSString*, NSObject*>* storage = [[ChromeEarlGrey
       userDefaultsObjectForKey:kDefaultBrowserKey] mutableCopy];
diff --git a/ios/chrome/browser/docking_promo/DEPS b/ios/chrome/browser/docking_promo/DEPS
index 4435d088..d54b1ee 100644
--- a/ios/chrome/browser/docking_promo/DEPS
+++ b/ios/chrome/browser/docking_promo/DEPS
@@ -5,5 +5,5 @@
   "+ios/chrome/browser/first_run/ui_bundled/first_run_screen_delegate.h",
   "+ios/chrome/browser/promos_manager/ui_bundled",
   "+ios/chrome/browser/start_surface/ui_bundled/start_surface_util.h",
-  "+ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h",
+  "+ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h",
 ]
diff --git a/ios/chrome/browser/docking_promo/ui/BUILD.gn b/ios/chrome/browser/docking_promo/ui/BUILD.gn
index 1efb954d..0e558e1 100644
--- a/ios/chrome/browser/docking_promo/ui/BUILD.gn
+++ b/ios/chrome/browser/docking_promo/ui/BUILD.gn
@@ -18,6 +18,7 @@
     "//ios/chrome/browser/promos_manager/model:types",
     "//ios/chrome/browser/promos_manager/ui_bundled:promos",
     "//ios/chrome/browser/shared/public/commands",
+    "//ios/chrome/browser/shared/ui/animated_promo",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/browser/tips_notifications/ui:shared",
     "//ios/chrome/common/ui/colors",
diff --git a/ios/chrome/browser/docking_promo/ui/docking_promo_view_controller.h b/ios/chrome/browser/docking_promo/ui/docking_promo_view_controller.h
index a6fbe52..6f6711c 100644
--- a/ios/chrome/browser/docking_promo/ui/docking_promo_view_controller.h
+++ b/ios/chrome/browser/docking_promo/ui/docking_promo_view_controller.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_DOCKING_PROMO_UI_DOCKING_PROMO_VIEW_CONTROLLER_H_
 #define IOS_CHROME_BROWSER_DOCKING_PROMO_UI_DOCKING_PROMO_VIEW_CONTROLLER_H_
 
-#import "ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h"
+#import "ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h"
 
 // Container view controller for the Docking Promo.
 @interface DockingPromoViewController : AnimatedPromoViewController
diff --git a/ios/chrome/browser/first_run/ui_bundled/best_features/ui/feature_highlight_screenshot_view_controller.h b/ios/chrome/browser/first_run/ui_bundled/best_features/ui/feature_highlight_screenshot_view_controller.h
index 40ccc29..96e03ca 100644
--- a/ios/chrome/browser/first_run/ui_bundled/best_features/ui/feature_highlight_screenshot_view_controller.h
+++ b/ios/chrome/browser/first_run/ui_bundled/best_features/ui/feature_highlight_screenshot_view_controller.h
@@ -12,6 +12,7 @@
 @protocol ConfirmationAlertActionHandler;
 
 // View for displaying a BestFeaturesItem.
+// TODO(crbug.com/433791509): Subclass from AnimatedPromoViewController.
 @interface FeatureHighlightScreenshotViewController
     : UIViewController <UINavigationControllerDelegate>
 
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index cc16cd2..077b4003 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1447,6 +1447,10 @@
      flag_descriptions::kAutofillCreditCardUploadName,
      flag_descriptions::kAutofillCreditCardUploadDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillUpstream)},
+    {"begin-cursor-at-point-tentative-fix",
+     flag_descriptions::kBeginCursorAtPointTentativeFixName,
+     flag_descriptions::kBeginCursorAtPointTentativeFixDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kBeginCursorAtPointTentativeFix)},
     {"use-sync-sandbox", flag_descriptions::kSyncSandboxName,
      flag_descriptions::kSyncSandboxDescription, flags_ui::kOsIos,
      SINGLE_VALUE_TYPE_AND_VALUE(
@@ -2804,6 +2808,9 @@
      flag_descriptions::kRcapsDynamicProfileCountryName,
      flag_descriptions::kRcapsDynamicProfileCountryDescription,
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(switches::kDynamicProfileCountry)},
+    {"cpe-signal-api", flag_descriptions::kCredentialProviderSignalAPIName,
+     flag_descriptions::kCredentialProviderSignalAPIDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kCredentialProviderSignalAPI)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 82db6f7..83a2399 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -249,6 +249,12 @@
     "When enabled, changes the amount of time required for VCN enrollment "
     "prompt strikes to expire.";
 
+const char kBeginCursorAtPointTentativeFixName[] =
+    "Begin cursor at point tentative fix";
+const char kBeginCursorAtPointTentativeFixDescription[] =
+    "A tentative fix for crbug.com/361003475. When enabled, it prevents a call to "
+    "setSelectedTextRange.";
+
 const char kBestFeaturesScreenInFirstRunName[] =
     "Display Best Features screen in the FRE";
 const char kBestFeaturesScreenInFirstRunDescription[] =
@@ -335,6 +341,11 @@
     "Enables a series of performance improvements for the Credential Provider "
     "Extension.";
 
+const char kCredentialProviderSignalAPIName[] =
+    "Credential Provider Signal API";
+const char kCredentialProviderSignalAPIDescription[] =
+    "Enables signal API for Passkeys in the Credential Provider Extension.";
+
 const char kMigrateIOSKeychainAccessibilityName[] =
     "Migrate iOS Keychain Accessibility";
 const char kMigrateIOSKeychainAccessibilityDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 59ce257..a2452e7 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -146,6 +146,9 @@
 extern const char kAutofillVcnEnrollStrikeExpiryTimeName[];
 extern const char kAutofillVcnEnrollStrikeExpiryTimeDescription[];
 
+extern const char kBeginCursorAtPointTentativeFixName[];
+extern const char kBeginCursorAtPointTentativeFixDescription[];
+
 extern const char kBestFeaturesScreenInFirstRunName[];
 extern const char kBestFeaturesScreenInFirstRunDescription[];
 
@@ -191,6 +194,9 @@
 extern const char kCredentialProviderPerformanceImprovementsName[];
 extern const char kCredentialProviderPerformanceImprovementsDescription[];
 
+extern const char kCredentialProviderSignalAPIName[];
+extern const char kCredentialProviderSignalAPIDescription[];
+
 extern const char kMigrateIOSKeychainAccessibilityName[];
 extern const char kMigrateIOSKeychainAccessibilityDescription[];
 
diff --git a/ios/chrome/browser/intelligence/bwg/model/BUILD.gn b/ios/chrome/browser/intelligence/bwg/model/BUILD.gn
index b2407f2..93853949 100644
--- a/ios/chrome/browser/intelligence/bwg/model/BUILD.gn
+++ b/ios/chrome/browser/intelligence/bwg/model/BUILD.gn
@@ -80,6 +80,7 @@
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/profile",
     "//ios/chrome/browser/signin/model:authentication_service",
+    "//ios/public/provider/chrome/browser/bwg:bwg_api",
     "//ios/web/public",
     "//ios/web/util",
   ]
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_service.h b/ios/chrome/browser/intelligence/bwg/model/bwg_service.h
index 1a588e4..b8746dd 100644
--- a/ios/chrome/browser/intelligence/bwg/model/bwg_service.h
+++ b/ios/chrome/browser/intelligence/bwg/model/bwg_service.h
@@ -45,6 +45,10 @@
 
   // The PrefService associated with the Profile.
   raw_ptr<PrefService> pref_service_ = nullptr;
+
+  // Whether the user is ineligible by the Gemini Enterprise policy (not Chrome
+  // Enterprise).
+  bool is_disabled_by_gemini_policy_ = false;
 };
 
 #endif  // IOS_CHROME_BROWSER_INTELLIGENCE_BWG_MODEL_BWG_SERVICE_H_
diff --git a/ios/chrome/browser/intelligence/bwg/model/bwg_service.mm b/ios/chrome/browser/intelligence/bwg/model/bwg_service.mm
index 4c92c981..867d5880 100644
--- a/ios/chrome/browser/intelligence/bwg/model/bwg_service.mm
+++ b/ios/chrome/browser/intelligence/bwg/model/bwg_service.mm
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/shared/model/prefs/pref_names.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/signin/model/authentication_service.h"
+#import "ios/public/provider/chrome/browser/bwg/bwg_api.h"
 #import "ios/web/public/web_state.h"
 #import "ios/web/util/content_type_util.h"
 
@@ -22,6 +23,10 @@
   auth_service_ = auth_service;
   identity_manager_ = identity_manager;
   pref_service_ = pref_service;
+
+  ios::provider::CheckGeminiEligibility(auth_service_, ^(BOOL eligible) {
+    is_disabled_by_gemini_policy_ = !eligible;
+  });
 }
 
 BwgService::~BwgService() = default;
@@ -40,9 +45,10 @@
                 signin::Tribool::kTrue
           : false;
 
-  // Checks the enterprise policy.
+  // Checks the Chrome and Gemini Enterprise policies.
   bool is_disabled_by_policy =
-      pref_service_->GetInteger(prefs::kGeminiEnabledByPolicy) == 1;
+      pref_service_->GetInteger(prefs::kGeminiEnabledByPolicy) == 1 ||
+      is_disabled_by_gemini_policy_;
 
   bool is_eligible = can_use_model_execution && !is_disabled_by_policy;
 
diff --git a/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm b/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm
index 4ba0f5e..13e30011 100644
--- a/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm
+++ b/ios/chrome/browser/lens_overlay/ui/lens_overlay_container_view_controller.mm
@@ -82,12 +82,14 @@
 - (void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
 
-  [self addChildViewController:_contentViewController];
-  _contentViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
-  [_borderView addSubview:_contentViewController.view];
-  [_contentViewController didMoveToParentViewController:self];
+  if (_contentViewController) {
+    [self addChildViewController:_contentViewController];
+    _contentViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
+    [_borderView addSubview:_contentViewController.view];
+    [_contentViewController didMoveToParentViewController:self];
 
-  AddSameConstraints(_contentViewController.view, _borderView);
+    AddSameConstraints(_contentViewController.view, _borderView);
+  }
 }
 
 - (void)viewWillDisappear:(BOOL)animated {
diff --git a/ios/chrome/browser/main/ui_bundled/BUILD.gn b/ios/chrome/browser/main/ui_bundled/BUILD.gn
index 1bf82407..b028b51 100644
--- a/ios/chrome/browser/main/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/main/ui_bundled/BUILD.gn
@@ -103,7 +103,7 @@
     # no headers from those target are included. They are however required as
     # the target exist to break circular dependencies or to provide resources.
     "//ios/chrome/app/resources:base_scene_storyboard",
-    "//ios/chrome/app/resources:launchscreen",
+    "//ios/chrome/app/resources:launchscreen_xib",
     "//ios/chrome/browser/tabs/model:tabs_internal",
   ]
 
diff --git a/ios/chrome/browser/metrics/model/ios_profile_session_durations_service.mm b/ios/chrome/browser/metrics/model/ios_profile_session_durations_service.mm
index a75909e..6c29158 100644
--- a/ios/chrome/browser/metrics/model/ios_profile_session_durations_service.mm
+++ b/ios/chrome/browser/metrics/model/ios_profile_session_durations_service.mm
@@ -26,8 +26,7 @@
           pref_service);
 
   password_metrics_recorder_ = std::make_unique<
-      password_manager::PasswordSessionDurationsMetricsRecorder>(pref_service,
-                                                                 sync_service);
+      password_manager::PasswordSessionDurationsMetricsRecorder>(sync_service);
 
   // `IOSProfileSessionDurationsService` is called explicitly each time a
   // session starts or ends. So there is no need to mimic what is done on
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h
index 189e1d5..7752b1a 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_consumer.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_NTP_UI_BUNDLED_NEW_TAB_PAGE_HEADER_CONSUMER_H_
 #define IOS_CHROME_BROWSER_NTP_UI_BUNDLED_NEW_TAB_PAGE_HEADER_CONSUMER_H_
 
-#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
 
 @protocol LogoVendor;
 @class NewTabPageColorPalette;
@@ -19,6 +19,10 @@
 // Exposes view and methods to drive the doodle.
 - (void)setLogoVendor:(id<LogoVendor>)logoVendor;
 
+// Sets the color for the monochrome logo. Pass `nil` to display the color
+// version.
+- (void)updateLogoColor:(UIColor*)logoTintColor;
+
 // Sets whether voice search is currently enabled.
 - (void)setVoiceSearchIsEnabled:(BOOL)voiceSearchIsEnabled;
 
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm
index 16449bf..8f0adcd 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_header_view_controller.mm
@@ -885,6 +885,18 @@
   [self updateLogoAndFakeboxDisplay];
 }
 
+- (void)updateLogoColor:(UIColor*)logoTintColor {
+  CHECK(_logoVendor);
+
+  if (logoTintColor) {
+    _logoVendor.usesMonochromeLogo = YES;
+    _logoVendor.view.tintColor = logoTintColor;
+  } else {
+    _logoVendor.usesMonochromeLogo = NO;
+    _logoVendor.view.tintColor = nil;
+  }
+}
+
 - (void)setVoiceSearchIsEnabled:(BOOL)voiceSearchIsEnabled {
   if (_voiceSearchIsEnabled == voiceSearchIsEnabled) {
     return;
diff --git a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm
index 32cabe0..aa5b01b 100644
--- a/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm
+++ b/ios/chrome/browser/ntp/ui_bundled/new_tab_page_mediator.mm
@@ -394,13 +394,14 @@
   if (colorTheme && colorTheme->color()) {
     // Sets the New Tab Page trait to a color palette generated from the current
     // theme.
-    [self.consumer.traitOverrides
-        setObject:CreateColorPaletteFromSeedColor(
-                      skia::UIColorFromSkColor(colorTheme->color()),
-                      ProtoEnumToSchemeVariant(
-                          colorTheme->browser_color_variant()))
-         forTrait:NewTabPageTrait.class];
+    NewTabPageColorPalette* colorPalette = CreateColorPaletteFromSeedColor(
+        skia::UIColorFromSkColor(colorTheme->color()),
+        ProtoEnumToSchemeVariant(colorTheme->browser_color_variant()));
+
+    [self.consumer.traitOverrides setObject:colorPalette
+                                   forTrait:NewTabPageTrait.class];
     [self.consumer setBackgroundImage:nil];
+    [self.headerConsumer updateLogoColor:colorPalette.tintColor];
     return;
   }
 
@@ -410,6 +411,7 @@
                                  forTrait:NewTabPageTrait.class];
   if (!background) {
     [self.consumer setBackgroundImage:nil];
+    [self.headerConsumer updateLogoColor:nil];
     return;
   }
 
@@ -605,6 +607,7 @@
 // image for the new tab page.
 - (void)handleBackgroundImageFetch:(const gfx::Image&)image {
   [self.consumer setBackgroundImage:image.ToUIImage()];
+  [self.headerConsumer updateLogoColor:UIColor.whiteColor];
 }
 
 @end
diff --git a/ios/chrome/browser/omnibox/public/omnibox_ui_features.cc b/ios/chrome/browser/omnibox/public/omnibox_ui_features.cc
index c51145c..2cb0bf8 100644
--- a/ios/chrome/browser/omnibox/public/omnibox_ui_features.cc
+++ b/ios/chrome/browser/omnibox/public/omnibox_ui_features.cc
@@ -15,3 +15,7 @@
 BASE_FEATURE(kIOSOmniboxAimShortcut,
              "IOSOmniboxAimShortcut",
              base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kBeginCursorAtPointTentativeFix,
+             "BeginCursorAtPointTentativeFix",
+             base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ios/chrome/browser/omnibox/public/omnibox_ui_features.h b/ios/chrome/browser/omnibox/public/omnibox_ui_features.h
index c048a07..b531635 100644
--- a/ios/chrome/browser/omnibox/public/omnibox_ui_features.h
+++ b/ios/chrome/browser/omnibox/public/omnibox_ui_features.h
@@ -14,4 +14,10 @@
 // Aim shortcut feature.
 BASE_DECLARE_FEATURE(kIOSOmniboxAimShortcut);
 
+// A tentative fix for crbug.com/361003475.
+BASE_DECLARE_FEATURE(kBeginCursorAtPointTentativeFix);
+
+// Returns whether rich autocompletion is enabled.
+bool IsRichAutocompletionEnabled();
+
 #endif  // IOS_CHROME_BROWSER_OMNIBOX_PUBLIC_OMNIBOX_UI_FEATURES_H_
diff --git a/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm b/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm
index 4bc5dd9..d5dd0a19 100644
--- a/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/omnibox/ui/omnibox_text_field_ios.mm
@@ -508,8 +508,10 @@
   // Exit preedit because it blocks the view of the textfield.
   [self exitPreEditState];
   // Remove selection and put the caret at the end of the string.
-  self.selectedTextRange = [self textRangeFromPosition:self.endOfDocument
-                                            toPosition:self.endOfDocument];
+  if (!base::FeatureList::IsEnabled(kBeginCursorAtPointTentativeFix)) {
+    self.selectedTextRange = [self textRangeFromPosition:self.endOfDocument
+                                              toPosition:self.endOfDocument];
+  }
   [super beginFloatingCursorAtPoint:point];
 }
 
diff --git a/ios/chrome/browser/passwords/model/ios_chrome_password_receiver_service_factory.mm b/ios/chrome/browser/passwords/model/ios_chrome_password_receiver_service_factory.mm
index 4ca811c..8ce200e 100644
--- a/ios/chrome/browser/passwords/model/ios_chrome_password_receiver_service_factory.mm
+++ b/ios/chrome/browser/passwords/model/ios_chrome_password_receiver_service_factory.mm
@@ -65,7 +65,7 @@
       DataTypeStoreServiceFactory::GetForProfile(profile)->GetStoreFactory());
 
   return std::make_unique<password_manager::PasswordReceiverServiceImpl>(
-      profile->GetPrefs(), std::move(sync_bridge),
+      std::move(sync_bridge),
       IOSChromeProfilePasswordStoreFactory::GetForProfile(
           profile, ServiceAccessType::EXPLICIT_ACCESS)
           .get(),
diff --git a/ios/chrome/browser/passwords/model/password_controller.mm b/ios/chrome/browser/passwords/model/password_controller.mm
index 46039037..dce9382 100644
--- a/ios/chrome/browser/passwords/model/password_controller.mm
+++ b/ios/chrome/browser/passwords/model/password_controller.mm
@@ -439,14 +439,13 @@
   }
 
   CHECK(self.profile);
-  PrefService* prefs = self.profile->GetPrefs();
   syncer::SyncService* syncService =
       SyncServiceFactory::GetForProfile(self.profile);
   const std::optional<std::string> accountToStorePassword =
-      password_manager::sync_util::GetAccountForSaving(prefs, syncService);
+      password_manager::sync_util::GetAccountForSaving(syncService);
   const password_manager::features_util::PasswordAccountStorageUserState
       accountStorageUserState = password_manager::features_util::
-          ComputePasswordAccountStorageUserState(prefs, syncService);
+          ComputePasswordAccountStorageUserState(syncService);
 
   infobars::InfoBarManager* infoBarManager =
       InfoBarManagerImpl::FromWebState(_webState);
diff --git a/ios/chrome/browser/policy/model/BUILD.gn b/ios/chrome/browser/policy/model/BUILD.gn
index 8d0139a6..2b87918 100644
--- a/ios/chrome/browser/policy/model/BUILD.gn
+++ b/ios/chrome/browser/policy/model/BUILD.gn
@@ -46,6 +46,8 @@
     "profile_policy_connector_factory.mm",
     "reporting/browser_report_generator_ios.h",
     "reporting/browser_report_generator_ios.mm",
+    "reporting/features.h",
+    "reporting/features.mm",
     "reporting/profile_report_generator_ios.h",
     "reporting/profile_report_generator_ios.mm",
     "reporting/report_scheduler_ios.h",
diff --git a/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm b/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm
index 245646d..3f172bc1 100644
--- a/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm
+++ b/ios/chrome/browser/policy/model/configuration_policy_handler_list_factory.mm
@@ -19,6 +19,7 @@
 #import "components/component_updater/pref_names.h"
 #import "components/content_settings/core/common/pref_names.h"
 #import "components/enterprise/browser/data_region/data_region_policy_handler.h"
+#import "components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.h"
 #import "components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.h"
 #import "components/enterprise/browser/reporting/cloud_reporting_policy_handler.h"
 #import "components/enterprise/browser/reporting/common_pref_names.h"
@@ -226,6 +227,9 @@
       std::make_unique<
           enterprise_reporting::CloudReportingFrequencyPolicyHandler>());
   handlers->AddHandler(
+      std::make_unique<
+          enterprise_reporting::CloudProfileReportingPolicyHandler>());
+  handlers->AddHandler(
       std::make_unique<policy::NewTabPageLocationPolicyHandler>());
   handlers->AddHandler(std::make_unique<policy::URLBlocklistPolicyHandler>(
       policy::key::kURLBlocklist));
diff --git a/ios/chrome/browser/policy/model/reporting/features.h b/ios/chrome/browser/policy/model/reporting/features.h
new file mode 100644
index 0000000..0793acc
--- /dev/null
+++ b/ios/chrome/browser/policy/model/reporting/features.h
@@ -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.
+
+#ifndef IOS_CHROME_BROWSER_POLICY_MODEL_REPORTING_FEATURES_H_
+#define IOS_CHROME_BROWSER_POLICY_MODEL_REPORTING_FEATURES_H_
+
+#import "base/feature_list.h"
+
+namespace enterprise_reporting {
+
+// Enables Cloud Profile Reporting on iOS.
+BASE_DECLARE_FEATURE(kCloudProfileReporting);
+
+}  // namespace enterprise_reporting
+
+#endif  // IOS_CHROME_BROWSER_POLICY_MODEL_REPORTING_FEATURES_H_
diff --git a/ios/chrome/browser/policy/model/reporting/features.mm b/ios/chrome/browser/policy/model/reporting/features.mm
new file mode 100644
index 0000000..9b961de
--- /dev/null
+++ b/ios/chrome/browser/policy/model/reporting/features.mm
@@ -0,0 +1,14 @@
+// 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/policy/model/reporting/features.h"
+
+namespace enterprise_reporting {
+
+// Enables Cloud Profile Reporting on iOS.
+BASE_FEATURE(kCloudProfileReporting,
+             "CloudProfileReporting",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace enterprise_reporting
diff --git a/ios/chrome/browser/price_insights/model/price_insights_model.h b/ios/chrome/browser/price_insights/model/price_insights_model.h
index 20f1ad6..36009b7 100644
--- a/ios/chrome/browser/price_insights/model/price_insights_model.h
+++ b/ios/chrome/browser/price_insights/model/price_insights_model.h
@@ -31,7 +31,7 @@
 struct PriceInsightsItemConfiguration
     : public ContextualPanelItemConfiguration {
   PriceInsightsItemConfiguration();
-  ~PriceInsightsItemConfiguration();
+  ~PriceInsightsItemConfiguration() override;
   explicit PriceInsightsItemConfiguration(
       PriceInsightsItemConfiguration* config);
 
diff --git a/ios/chrome/browser/providers/bwg/chromium_bwg.mm b/ios/chrome/browser/providers/bwg/chromium_bwg.mm
index b1ed1c6..3b8a0cd6 100644
--- a/ios/chrome/browser/providers/bwg/chromium_bwg.mm
+++ b/ios/chrome/browser/providers/bwg/chromium_bwg.mm
@@ -29,4 +29,7 @@
   return nil;
 }
 
+void CheckGeminiEligibility(AuthenticationService* auth_service,
+                            BWGEligibilityCallback completion) {}
+
 }  // namespace ios::provider
diff --git a/ios/chrome/browser/reader_mode/model/BUILD.gn b/ios/chrome/browser/reader_mode/model/BUILD.gn
index 5a38aff..2e67488 100644
--- a/ios/chrome/browser/reader_mode/model/BUILD.gn
+++ b/ios/chrome/browser/reader_mode/model/BUILD.gn
@@ -23,6 +23,8 @@
     "reader_mode_model.mm",
     "reader_mode_model_factory.h",
     "reader_mode_model_factory.mm",
+    "reader_mode_panel_item_configuration.h",
+    "reader_mode_panel_item_configuration.mm",
     "reader_mode_tab_helper.h",
     "reader_mode_tab_helper.mm",
   ]
@@ -42,6 +44,8 @@
     "//ios/chrome/browser/contextual_panel/model:public",
     "//ios/chrome/browser/crash_report/model",
     "//ios/chrome/browser/dom_distiller/model",
+    "//ios/chrome/browser/intelligence/bwg/model:bwg_service",
+    "//ios/chrome/browser/intelligence/bwg/model:bwg_service_factory",
     "//ios/chrome/browser/overlays/model",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
diff --git a/ios/chrome/browser/reader_mode/model/DEPS b/ios/chrome/browser/reader_mode/model/DEPS
index fe3566f..2507f0a 100644
--- a/ios/chrome/browser/reader_mode/model/DEPS
+++ b/ios/chrome/browser/reader_mode/model/DEPS
@@ -9,6 +9,7 @@
   "+third_party/dom_distiller_js",
   "+ios/web/navigation/wk_navigation_util.h",
   "+ios/chrome/browser/web/model/web_view_proxy/web_view_proxy_tab_helper.h",
+  "+ios/chrome/browser/intelligence/bwg/model",
 ]
 specific_include_rules = {
   "^reader_mode_test.mm" : [
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_model.mm b/ios/chrome/browser/reader_mode/model/reader_mode_model.mm
index 32a1afe..13183ec3 100644
--- a/ios/chrome/browser/reader_mode/model/reader_mode_model.mm
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_model.mm
@@ -4,34 +4,12 @@
 
 #import "ios/chrome/browser/reader_mode/model/reader_mode_model.h"
 
-#import "base/strings/sys_string_conversions.h"
-#import "ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.h"
-#import "ios/chrome/browser/contextual_panel/model/contextual_panel_item_type.h"
-#import "ios/chrome/browser/reader_mode/model/constants.h"
+#import "ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.h"
 #import "ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.h"
-#import "ios/chrome/grit/ios_strings.h"
 #import "ios/web/public/web_state.h"
-#import "ui/base/l10n/l10n_util.h"
 
 namespace {
 
-// Duration for which the large entrypoint is displayed.
-const base::TimeDelta kLargeEntrypointDisplayedDuration = base::Seconds(4);
-
-// Performs the custom Reader mode contextual chip entrypoint for `web_state`.
-void PerformReaderModeCustomEntrypointAction(
-    base::WeakPtr<web::WebState> web_state) {
-  if (!web_state || web_state->IsBeingDestroyed()) {
-    return;
-  }
-  ReaderModeTabHelper* reader_mode_tab_helper =
-      ReaderModeTabHelper::FromWebState(web_state.get());
-  if (!reader_mode_tab_helper) {
-    return;
-  }
-  reader_mode_tab_helper->SetActive(true);
-}
-
 // Calls `callback` with the appropriate ContextualPanelItemConfiguration object
 // depend on the value of `current_page_supports_reader_mode`.
 void HandleCurrentPageSupportsReaderModeResult(
@@ -41,22 +19,8 @@
   std::unique_ptr<ContextualPanelItemConfiguration> configuration;
   if (web_state && current_page_supports_reader_mode &&
       *current_page_supports_reader_mode) {
-    configuration = std::make_unique<ContextualPanelItemConfiguration>(
-        ContextualPanelItemType::ReaderModeItem);
-    configuration->entrypoint_message = l10n_util::GetStringUTF8(
-        IDS_IOS_CONTEXTUAL_PANEL_READER_MODE_MODEL_ENTRYPOINT_MESSAGE);
-    configuration->entrypoint_message_large_entrypoint_always_shown = true;
-    configuration->accessibility_label = l10n_util::GetStringUTF8(
-        IDS_IOS_CONTEXTUAL_PANEL_READER_MODE_MODEL_ENTRYPOINT_MESSAGE);
-    configuration->entrypoint_image_name =
-        base::SysNSStringToUTF8(GetReaderModeSymbolName());
-    configuration->image_type =
-        ContextualPanelItemConfiguration::EntrypointImageType::SFSymbol;
-    configuration->relevance = ContextualPanelItemConfiguration::low_relevance;
-    configuration->entrypoint_custom_action = base::BindRepeating(
-        &PerformReaderModeCustomEntrypointAction, web_state->GetWeakPtr());
-    configuration->large_entrypoint_displayed_duration =
-        kLargeEntrypointDisplayedDuration;
+    configuration =
+        std::make_unique<ReaderModePanelItemConfiguration>(web_state.get());
   }
   base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), std::move(configuration)));
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.h b/ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.h
new file mode 100644
index 0000000..ba20637
--- /dev/null
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.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 IOS_CHROME_BROWSER_READER_MODE_MODEL_READER_MODE_PANEL_ITEM_CONFIGURATION_H_
+#define IOS_CHROME_BROWSER_READER_MODE_MODEL_READER_MODE_PANEL_ITEM_CONFIGURATION_H_
+
+#import "base/scoped_observation.h"
+#import "ios/chrome/browser/contextual_panel/model/contextual_panel_item_configuration.h"
+#import "ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.h"
+#import "ios/web/public/web_state_observer.h"
+
+// Configuration for the Reader Mode item in the contextual panel.
+// This object observes the WebState and the ReaderModeTabHelper to manage its
+// own lifecycle.
+class ReaderModePanelItemConfiguration
+    : public ContextualPanelItemConfiguration,
+      public web::WebStateObserver,
+      public ReaderModeTabHelper::Observer {
+ public:
+  explicit ReaderModePanelItemConfiguration(web::WebState* web_state);
+  ~ReaderModePanelItemConfiguration() override;
+
+  // ContextualPanelItemConfiguration
+  void DidTransitionToSmallEntrypoint() override;
+
+  // ReaderModeTabHelper::Observer
+  void ReaderModeTabHelperDestroyed(ReaderModeTabHelper* tab_helper) override;
+  void ReaderModeWebStateDidLoadContent(
+      ReaderModeTabHelper* tab_helper) override;
+  void ReaderModeWebStateWillBecomeUnavailable(
+      ReaderModeTabHelper* tab_helper) override;
+  void ReaderModeDistillationFailed(ReaderModeTabHelper* tab_helper) override;
+
+  // web::WebStateObserver
+  void WebStateDestroyed(web::WebState* web_state) override;
+
+ private:
+  base::ScopedObservation<web::WebState, web::WebStateObserver>
+      web_state_observation_{this};
+  base::ScopedObservation<ReaderModeTabHelper, ReaderModeTabHelper::Observer>
+      reader_mode_tab_helper_observation_{this};
+};
+
+#endif  // IOS_CHROME_BROWSER_READER_MODE_MODEL_READER_MODE_PANEL_ITEM_CONFIGURATION_H_
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.mm b/ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.mm
new file mode 100644
index 0000000..43a1dba8
--- /dev/null
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_panel_item_configuration.mm
@@ -0,0 +1,116 @@
+// 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/reader_mode/model/reader_mode_panel_item_configuration.h"
+
+#import "base/strings/sys_string_conversions.h"
+#import "ios/chrome/browser/contextual_panel/model/contextual_panel_item_type.h"
+#import "ios/chrome/browser/contextual_panel/model/contextual_panel_tab_helper.h"
+#import "ios/chrome/browser/intelligence/bwg/model/bwg_service.h"
+#import "ios/chrome/browser/intelligence/bwg/model/bwg_service_factory.h"
+#import "ios/chrome/browser/reader_mode/model/constants.h"
+#import "ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+#import "ios/chrome/grit/ios_strings.h"
+#import "ios/web/public/web_state.h"
+#import "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// Duration for which the large entrypoint is displayed.
+const base::TimeDelta kLargeEntrypointDisplayedDuration = base::Seconds(4);
+
+// Activates Reader mode in the `web_state` if possible.
+void ActivateReaderModeInWebState(base::WeakPtr<web::WebState> web_state) {
+  if (!web_state || web_state->IsBeingDestroyed()) {
+    return;
+  }
+  ReaderModeTabHelper* reader_mode_tab_helper =
+      ReaderModeTabHelper::FromWebState(web_state.get());
+  if (reader_mode_tab_helper) {
+    reader_mode_tab_helper->SetActive(true);
+  }
+}
+
+}  // namespace
+
+ReaderModePanelItemConfiguration::ReaderModePanelItemConfiguration(
+    web::WebState* web_state)
+    : ContextualPanelItemConfiguration(
+          ContextualPanelItemType::ReaderModeItem) {
+  entrypoint_message = l10n_util::GetStringUTF8(
+      IDS_IOS_CONTEXTUAL_PANEL_READER_MODE_MODEL_ENTRYPOINT_MESSAGE);
+  entrypoint_message_large_entrypoint_always_shown = true;
+  accessibility_label = l10n_util::GetStringUTF8(
+      IDS_IOS_CONTEXTUAL_PANEL_READER_MODE_MODEL_ENTRYPOINT_MESSAGE);
+  entrypoint_image_name = base::SysNSStringToUTF8(GetReaderModeSymbolName());
+  image_type = ContextualPanelItemConfiguration::EntrypointImageType::SFSymbol;
+  relevance = ContextualPanelItemConfiguration::low_relevance;
+  entrypoint_custom_action =
+      base::BindRepeating(&ActivateReaderModeInWebState, web_state->GetWeakPtr());
+  large_entrypoint_displayed_duration = kLargeEntrypointDisplayedDuration;
+
+  ReaderModeTabHelper* reader_mode_tab_helper =
+      ReaderModeTabHelper::FromWebState(web_state);
+  DCHECK(reader_mode_tab_helper);
+  reader_mode_tab_helper_observation_.Observe(reader_mode_tab_helper);
+  web_state_observation_.Observe(web_state);
+}
+
+ReaderModePanelItemConfiguration::~ReaderModePanelItemConfiguration() = default;
+
+#pragma mark - ContextualPanelItemConfiguration
+
+void ReaderModePanelItemConfiguration::DidTransitionToSmallEntrypoint() {
+  web::WebState* web_state = web_state_observation_.GetSource();
+  if (!web_state || web_state->IsBeingDestroyed()) {
+    return;
+  }
+  ProfileIOS* profile =
+      ProfileIOS::FromBrowserState(web_state->GetBrowserState());
+  BwgService* bwg_service = BwgServiceFactory::GetForProfile(profile);
+  if (!bwg_service || !bwg_service->IsBwgAvailableForWebState(web_state)) {
+    return;
+  }
+  ContextualPanelTabHelper* contextual_panel_tab_helper =
+      ContextualPanelTabHelper::FromWebState(web_state);
+  if (contextual_panel_tab_helper) {
+    contextual_panel_tab_helper->InvalidateContextualPanelItemConfiguration(
+        this);
+  }
+}
+
+#pragma mark - ReaderModeTabHelper::Observer
+
+void ReaderModePanelItemConfiguration::ReaderModeTabHelperDestroyed(
+    ReaderModeTabHelper* tab_helper) {
+  reader_mode_tab_helper_observation_.Reset();
+}
+
+void ReaderModePanelItemConfiguration::ReaderModeWebStateDidLoadContent(
+    ReaderModeTabHelper* tab_helper) {}
+
+void ReaderModePanelItemConfiguration::ReaderModeWebStateWillBecomeUnavailable(
+    ReaderModeTabHelper* tab_helper) {}
+
+void ReaderModePanelItemConfiguration::ReaderModeDistillationFailed(
+    ReaderModeTabHelper* tab_helper) {
+  web::WebState* web_state = web_state_observation_.GetSource();
+  if (!web_state || web_state->IsBeingDestroyed()) {
+    return;
+  }
+  ContextualPanelTabHelper* contextual_panel_tab_helper =
+      ContextualPanelTabHelper::FromWebState(web_state);
+  if (contextual_panel_tab_helper) {
+    contextual_panel_tab_helper->InvalidateContextualPanelItemConfiguration(
+        this);
+  }
+}
+
+#pragma mark - web::WebStateObserver
+
+void ReaderModePanelItemConfiguration::WebStateDestroyed(
+    web::WebState* web_state) {
+  web_state_observation_.Reset();
+}
diff --git a/ios/chrome/browser/reader_mode/ui/reader_mode_egtest.mm b/ios/chrome/browser/reader_mode/ui/reader_mode_egtest.mm
index 7fdf3ab..744febd 100644
--- a/ios/chrome/browser/reader_mode/ui/reader_mode_egtest.mm
+++ b/ios/chrome/browser/reader_mode/ui/reader_mode_egtest.mm
@@ -775,4 +775,26 @@
   [ChromeEarlGrey verifyAccessibilityForCurrentScreen];
 }
 
+// Tests that the contextual panel entrypoint disappears when distillation
+// fails.
+- (void)testContextualPanelEntrypointDisappearsOnDistillationFailure {
+  [ChromeEarlGrey loadURL:self.testServer->GetURL("/article.html")];
+  [ChromeEarlGrey waitForPageToFinishLoading];
+
+  // Wait for the contextual panel entrypoint to appear.
+  id<GREYMatcher> entrypoint = chrome_test_util::ButtonWithAccessibilityLabelId(
+      IDS_IOS_CONTEXTUAL_PANEL_READER_MODE_MODEL_ENTRYPOINT_MESSAGE);
+  [ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher:entrypoint];
+
+  // Make the page not distillable.
+  [ChromeEarlGrey
+      evaluateJavaScriptForSideEffect:@"document.body.outerHTML = ''"];
+
+  // Tap the entrypoint to trigger distillation.
+  [[EarlGrey selectElementWithMatcher:entrypoint] performAction:grey_tap()];
+
+  // The entrypoint should disappear.
+  [ChromeEarlGrey waitForUIElementToDisappearWithMatcher:entrypoint];
+}
+
 @end
diff --git a/ios/chrome/browser/reading_list/ui_bundled/BUILD.gn b/ios/chrome/browser/reading_list/ui_bundled/BUILD.gn
index 2f576493..1256571 100644
--- a/ios/chrome/browser/reading_list/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/reading_list/ui_bundled/BUILD.gn
@@ -206,8 +206,11 @@
     "//ios/chrome/browser/feature_engagement/model",
     "//ios/chrome/browser/net/model:crurl",
     "//ios/chrome/browser/reading_list/model",
+    "//ios/chrome/browser/shared/model/profile/test",
     "//ios/chrome/browser/shared/ui/table_view:styler",
     "//ios/chrome/browser/shared/ui/table_view/cells",
+    "//ios/chrome/browser/signin/model:authentication_service_factory",
+    "//ios/chrome/browser/signin/model:test_support",
     "//ios/chrome/browser/tabs/model",
     "//ios/chrome/test/fakes",
     "//ios/web",
diff --git a/ios/chrome/browser/reading_list/ui_bundled/reading_list_coordinator.mm b/ios/chrome/browser/reading_list/ui_bundled/reading_list_coordinator.mm
index 0c82cdb..e373a5b 100644
--- a/ios/chrome/browser/reading_list/ui_bundled/reading_list_coordinator.mm
+++ b/ios/chrome/browser/reading_list/ui_bundled/reading_list_coordinator.mm
@@ -65,6 +65,7 @@
 #import "ios/chrome/browser/sharing/ui_bundled/sharing_params.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/authentication_service_observer_bridge.h"
 #import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/signin/model/identity_manager_factory.h"
 #import "ios/chrome/browser/sync/model/sync_service_factory.h"
@@ -82,6 +83,7 @@
 // we can move the SigninPromoViewConsumer implementation from the coordinator
 // to the view.
 @interface ReadingListCoordinator () <AccountSettingsPresenter,
+                                      AuthenticationServiceObserving,
                                       IdentityManagerObserverBridgeDelegate,
                                       ReadingListMenuProvider,
                                       ReadingListListItemFactoryDelegate,
@@ -118,6 +120,9 @@
   id<ApplicationCommands> _applicationCommandsHandler;
   // Authentication Service to retrieve the user's signed-in state.
   raw_ptr<AuthenticationService> _authService;
+  // Observer for auth service status changes.
+  std::unique_ptr<AuthenticationServiceObserverBridge>
+      _authServiceObserverBridge;
   // Service to retrieve preference values.
   raw_ptr<PrefService> _prefService;
   // Manager for user's Google identities.
@@ -156,6 +161,8 @@
   _applicationCommandsHandler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), ApplicationCommands);
   _authService = AuthenticationServiceFactory::GetForProfile(profile);
+  _authServiceObserverBridge =
+      std::make_unique<AuthenticationServiceObserverBridge>(_authService, self);
   _identityManager = IdentityManagerFactory::GetForProfile(profile);
   _prefService = profile->GetPrefs();
 
@@ -649,6 +656,12 @@
   }
 }
 
+#pragma mark - AuthenticationServiceObserving
+
+- (void)onServiceStatusChanged {
+  [self updateSignInPromoVisibility];
+}
+
 #pragma mark - Private
 
 - (void)dismissReadingList {
diff --git a/ios/chrome/browser/reading_list/ui_bundled/reading_list_mediator_unittest.mm b/ios/chrome/browser/reading_list/ui_bundled/reading_list_mediator_unittest.mm
index 4bb630a..14c44db 100644
--- a/ios/chrome/browser/reading_list/ui_bundled/reading_list_mediator_unittest.mm
+++ b/ios/chrome/browser/reading_list/ui_bundled/reading_list_mediator_unittest.mm
@@ -22,6 +22,9 @@
 #import "ios/chrome/browser/reading_list/ui_bundled/reading_list_list_item_custom_action_factory.h"
 #import "ios/chrome/browser/reading_list/ui_bundled/reading_list_list_item_factory.h"
 #import "ios/chrome/browser/reading_list/ui_bundled/reading_list_table_view_item.h"
+#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
+#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
+#import "ios/chrome/browser/signin/model/fake_authentication_service_delegate.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
diff --git a/ios/chrome/browser/safari_data_import/coordinator/BUILD.gn b/ios/chrome/browser/safari_data_import/coordinator/BUILD.gn
index 5331f91d..bb145168 100644
--- a/ios/chrome/browser/safari_data_import/coordinator/BUILD.gn
+++ b/ios/chrome/browser/safari_data_import/coordinator/BUILD.gn
@@ -53,10 +53,28 @@
   deps = [
     ":coordinator_delegate",
     "//base",
+    "//components/application_locale_storage",
+    "//components/autofill/core/browser",
+    "//components/bookmarks/browser",
+    "//components/history/core/browser",
+    "//components/keyed_service/core",
+    "//components/password_manager/core/browser/ui",
+    "//components/reading_list/core",
+    "//components/user_data_importer/ios",
+    "//ios/chrome/browser/affiliations/model",
+    "//ios/chrome/browser/autofill/model",
+    "//ios/chrome/browser/bookmarks/model",
     "//ios/chrome/browser/first_run/ui_bundled:constants",
+    "//ios/chrome/browser/history/model",
+    "//ios/chrome/browser/passwords/model:store_factory",
+    "//ios/chrome/browser/reading_list/model",
+    "//ios/chrome/browser/safari_data_import/model",
     "//ios/chrome/browser/safari_data_import/public",
     "//ios/chrome/browser/safari_data_import/ui",
+    "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
+    "//ios/chrome/browser/shared/model/profile",
+    "//ios/chrome/browser/webauthn/model",
     "//ios/chrome/common/ui/promo_style",
   ]
 }
diff --git a/ios/chrome/browser/safari_data_import/coordinator/DEPS b/ios/chrome/browser/safari_data_import/coordinator/DEPS
index 3c47076..8191f94 100644
--- a/ios/chrome/browser/safari_data_import/coordinator/DEPS
+++ b/ios/chrome/browser/safari_data_import/coordinator/DEPS
@@ -1,7 +1,13 @@
 include_rules = [
+  "+ios/chrome/browser/affiliations/model",
+  "+ios/chrome/browser/autofill/model",
+  "+ios/chrome/browser/bookmarks/model",
   "+ios/chrome/browser/feature_engagement/model",
   "+ios/chrome/browser/first_run/ui_bundled/first_run_constants.h",
-  "+ios/chrome/browser/passwords/model/features.h",
+  "+ios/chrome/browser/history/model",
+  "+ios/chrome/browser/passwords/model",
   "+ios/chrome/browser/promos_manager",
+  "+ios/chrome/browser/reading_list/model",
   "+ios/chrome/browser/scoped_ui_blocker/ui_bundled",
+  "+ios/chrome/browser/webauthn/model",
 ]
diff --git a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_coordinator.mm b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_coordinator.mm
index 0cbc8b90..62e5b13 100644
--- a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_coordinator.mm
+++ b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_coordinator.mm
@@ -8,6 +8,20 @@
 
 #import "base/check_op.h"
 #import "base/notreached.h"
+#import "components/autofill/core/browser/data_manager/payments/payments_data_manager.h"
+#import "components/autofill/core/browser/data_manager/personal_data_manager.h"
+#import "components/bookmarks/browser/bookmark_model.h"
+#import "components/history/core/browser/history_service.h"
+#import "components/keyed_service/core/service_access_type.h"
+#import "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+#import "components/reading_list/core/reading_list_model.h"
+#import "ios/chrome/browser/affiliations/model/ios_chrome_affiliation_service_factory.h"
+#import "ios/chrome/browser/autofill/model/personal_data_manager_factory.h"
+#import "ios/chrome/browser/bookmarks/model/bookmark_model_factory.h"
+#import "ios/chrome/browser/history/model/history_service_factory.h"
+#import "ios/chrome/browser/passwords/model/ios_chrome_account_password_store_factory.h"
+#import "ios/chrome/browser/passwords/model/ios_chrome_profile_password_store_factory.h"
+#import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h"
 #import "ios/chrome/browser/safari_data_import/coordinator/safari_data_import_child_coordinator_delegate.h"
 #import "ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.h"
 #import "ios/chrome/browser/safari_data_import/public/password_import_item.h"
@@ -16,6 +30,8 @@
 #import "ios/chrome/browser/safari_data_import/ui/safari_data_import_password_conflict_resolution_view_controller.h"
 #import "ios/chrome/browser/safari_data_import/ui/safari_data_item_table_view.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
+#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
+#import "ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h"
 #import "ios/chrome/common/ui/promo_style/promo_style_view_controller_delegate.h"
 
 @interface SafariDataImportImportCoordinator () <
@@ -26,7 +42,8 @@
   /// The view controller pushed onto the base navigation controller; user
   /// interacts with it to present other views.
   SafariDataImportImportViewController* _containerViewController;
-  /// The mediator handling the interaction with the model.
+  /// The mediator handling the interaction with the model. Lazily loaded with
+  /// `-mediator` method.
   SafariDataImportImportMediator* _mediator;
   /// File picker for the user to select Safari data.
   UIDocumentPickerViewController* _documentProvider;
@@ -54,15 +71,13 @@
   _tableView = [[SafariDataItemTableView alloc] init];
   _tableView.importStageConsumer = _containerViewController;
   _containerViewController.itemTableView = _tableView;
-  _mediator = [[SafariDataImportImportMediator alloc] init];
-  _mediator.importStageConsumer = _containerViewController;
-  _mediator.itemConsumer = _tableView;
   self.baseNavigationController.navigationBarHidden = NO;
   [self.baseNavigationController pushViewController:_containerViewController
                                            animated:YES];
 }
 
 - (void)stop {
+  [[self mediator] disconnect];
   self.delegate = nil;
   _containerViewController = nil;
 }
@@ -100,6 +115,43 @@
 
 #pragma mark - Private
 
+/// Lazily-loaded mediator.
+- (SafariDataImportImportMediator*)mediator {
+  if (!_mediator) {
+    /// Retrieve mediator dependencies.
+    ProfileIOS* profile = self.profile->GetOriginalProfile();
+    std::unique_ptr<password_manager::SavedPasswordsPresenter>
+        savedPasswordsPresenter =
+            std::make_unique<password_manager::SavedPasswordsPresenter>(
+                IOSChromeAffiliationServiceFactory::GetForProfile(profile),
+                IOSChromeProfilePasswordStoreFactory::GetForProfile(
+                    profile, ServiceAccessType::EXPLICIT_ACCESS),
+                IOSChromeAccountPasswordStoreFactory::GetForProfile(
+                    profile, ServiceAccessType::EXPLICIT_ACCESS),
+                /*passkey_model=*/nullptr);
+    autofill::PersonalDataManager* personalDataManager =
+        autofill::PersonalDataManagerFactory::GetForProfile(profile);
+    history::HistoryService* historyService =
+        ios::HistoryServiceFactory::GetForProfile(
+            profile, ServiceAccessType::EXPLICIT_ACCESS);
+    bookmarks::BookmarkModel* bookmarkModel =
+        ios::BookmarkModelFactory::GetForProfile(profile);
+    ReadingListModel* readingListModel =
+        ReadingListModelFactory::GetForProfile(profile);
+    /// Initialize mediator.
+    _mediator = [[SafariDataImportImportMediator alloc]
+        initWithSavedPasswordsPresenter:std::move(savedPasswordsPresenter)
+                    paymentsDataManager:&personalDataManager
+                                             ->payments_data_manager()
+                         historyService:historyService
+                          bookmarkModel:bookmarkModel
+                       readingListModel:readingListModel];
+    _mediator.importStageConsumer = _containerViewController;
+    _mediator.itemConsumer = _tableView;
+  }
+  return _mediator;
+}
+
 /// Displays the document picker so the user could select the Safari data file.
 - (void)showFilePicker {
   if (_documentProvider && (_documentProvider.isBeingPresented ||
@@ -116,7 +168,7 @@
                                                create:NO
                                                 error:nil];
   _documentProvider.allowsMultipleSelection = NO;
-  _documentProvider.delegate = _mediator;
+  _documentProvider.delegate = [self mediator];
   _documentProvider.modalPresentationStyle =
       UIModalPresentationOverCurrentContext;
   [_containerViewController presentViewController:_documentProvider
diff --git a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.h b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.h
index 325d8a115..f369683 100644
--- a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.h
+++ b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.h
@@ -7,6 +7,20 @@
 
 #import <UIKit/UIKit.h>
 
+#import <memory>
+
+#import "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+
+namespace autofill {
+class PaymentsDataManager;
+}
+namespace bookmarks {
+class BookmarkModel;
+}
+namespace history {
+class HistoryService;
+}
+class ReadingListModel;
 @protocol SafariDataImportImportStageConsumer;
 @protocol SafariDataItemConsumer;
 
@@ -14,13 +28,32 @@
 /// .zip file generated from Safari data to Chrome.
 @interface SafariDataImportImportMediator : NSObject <UIDocumentPickerDelegate>
 
-/// Consumer object handling import stage transitions.
+/// Consumer object handling import stage transitions. This needs to be set
+/// before selecting a file.
 @property(nonatomic, weak) id<SafariDataImportImportStageConsumer>
     importStageConsumer;
 
-/// Consumer object displaying Safari item import status.
+/// Consumer object displaying Safari item import status. This needs to be set
+/// before selecting a file.
 @property(nonatomic, weak) id<SafariDataItemConsumer> itemConsumer;
 
+/// Initializer.
+- (instancetype)
+    initWithSavedPasswordsPresenter:
+        (std::unique_ptr<password_manager::SavedPasswordsPresenter>)
+            savedPasswordsPresenter
+                paymentsDataManager:
+                    (autofill::PaymentsDataManager*)paymentsDataManager
+                     historyService:(history::HistoryService*)historyService
+                      bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
+                   readingListModel:(ReadingListModel*)readingListModel
+    NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Disconnect mediator dependencies; needs to be invoked before deallocating
+/// the coordinator.
+- (void)disconnect;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_SAFARI_DATA_IMPORT_COORDINATOR_SAFARI_DATA_IMPORT_IMPORT_MEDIATOR_H_
diff --git a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.mm b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.mm
index d786d27..54cd139 100644
--- a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.mm
+++ b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.mm
@@ -4,44 +4,78 @@
 
 #import "ios/chrome/browser/safari_data_import/coordinator/safari_data_import_import_mediator.h"
 
+#import "base/apple/foundation_util.h"
+#import "base/check.h"
+#import "components/application_locale_storage/application_locale_storage.h"
+#import "components/user_data_importer/ios/ios_bookmark_parser.h"
+#import "components/user_data_importer/utility/safari_data_importer.h"
+#import "ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.h"
 #import "ios/chrome/browser/safari_data_import/public/safari_data_import_stage.h"
 #import "ios/chrome/browser/safari_data_import/public/safari_data_item.h"
 #import "ios/chrome/browser/safari_data_import/public/safari_data_item_consumer.h"
 #import "ios/chrome/browser/safari_data_import/ui/safari_data_import_import_stage_consumer.h"
+#import "ios/chrome/browser/shared/model/application_context/application_context.h"
 
 @implementation SafariDataImportImportMediator {
-  /// Whether the file loading process has started.
-  BOOL _fileStartedToLoad;
+  /// The importer instance and the client.
+  std::unique_ptr<user_data_importer::SafariDataImporter> _importer;
+  std::unique_ptr<IOSSafariDataImportClient> _importClient;
+  /// The `SavedPasswordsPresenter` instance being used by the imported. Needs
+  /// to be kept alive in the duration of the importer.
+  std::unique_ptr<password_manager::SavedPasswordsPresenter>
+      _savedPasswordsPresenter;
+  /// The file being processed.
+  NSURL* _file;
+  /// Whether the mediator is disconnected.
+  BOOL _disconnected;
+}
+
+- (instancetype)
+    initWithSavedPasswordsPresenter:
+        (std::unique_ptr<password_manager::SavedPasswordsPresenter>)
+            savedPasswordsPresenter
+                paymentsDataManager:
+                    (autofill::PaymentsDataManager*)paymentsDataManager
+                     historyService:(history::HistoryService*)historyService
+                      bookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
+                   readingListModel:(ReadingListModel*)readingListModel {
+  self = [super init];
+  if (self) {
+    _importClient = std::make_unique<IOSSafariDataImportClient>();
+    _savedPasswordsPresenter = std::move(savedPasswordsPresenter);
+    std::unique_ptr<user_data_importer::IOSBookmarkParser> bookmarkParser =
+        std::make_unique<user_data_importer::IOSBookmarkParser>();
+    std::string locale =
+        GetApplicationContext()->GetApplicationLocaleStorage()->Get();
+    _importer = std::make_unique<user_data_importer::SafariDataImporter>(
+        _importClient.get(), _savedPasswordsPresenter.get(),
+        paymentsDataManager, historyService, bookmarkModel, readingListModel,
+        std::move(bookmarkParser), locale);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  CHECK(_disconnected, base::NotFatalUntil::M143);
+}
+
+- (void)disconnect {
+  _importer.reset();
+  _savedPasswordsPresenter.reset();
+  _importClient.reset();
+  _disconnected = YES;
 }
 
 #pragma mark - UIDocumentPickerDelegate
 
 - (void)documentPicker:(UIDocumentPickerViewController*)controller
     didPickDocumentsAtURLs:(NSArray<NSURL*>*)urls {
-  if (_fileStartedToLoad) {
+  if (_file) {
     return;
   }
-  _fileStartedToLoad = YES;
-  /// TODO(crbug.com/420703283): This is a temporary code snippet for
-  /// `SafariDataItem` demonstration purpose. Replace with actual logic to
-  /// import the file and call `importPreparationDidComplete`.
-  __weak __typeof(self) weakSelf = self;
-  dispatch_after(
-      dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),
-      dispatch_get_main_queue(), ^{
-        [weakSelf.itemConsumer
-            populateItem:[[SafariDataItem alloc]
-                             initWithType:SafariDataItemType::kPasswords]];
-        [weakSelf.itemConsumer
-            populateItem:[[SafariDataItem alloc]
-                             initWithType:SafariDataItemType::kHistory]];
-        [weakSelf.itemConsumer
-            populateItem:[[SafariDataItem alloc]
-                             initWithType:SafariDataItemType::kBookmarks]];
-        [weakSelf.itemConsumer
-            populateItem:[[SafariDataItem alloc]
-                             initWithType:SafariDataItemType::kPayment]];
-      });
+  _file = urls[0];
+  _importClient->SetSafariDataItemConsumer(self.itemConsumer);
+  _importer->PrepareImport(base::apple::NSURLToFilePath(_file));
 }
 
 - (void)documentPickerWasCancelled:(UIDocumentPickerViewController*)controller {
diff --git a/ios/chrome/browser/safari_data_import/model/BUILD.gn b/ios/chrome/browser/safari_data_import/model/BUILD.gn
new file mode 100644
index 0000000..586d20b
--- /dev/null
+++ b/ios/chrome/browser/safari_data_import/model/BUILD.gn
@@ -0,0 +1,28 @@
+# 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.
+
+source_set("model") {
+  sources = [
+    "ios_safari_data_import_client.h",
+    "ios_safari_data_import_client.mm",
+  ]
+  public_deps =
+      [ "//components/user_data_importer/utility:safari_data_importer" ]
+  deps = [
+    "//base",
+    "//components/password_manager/core/browser/import:importer",
+    "//ios/chrome/browser/safari_data_import/public",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "ios_safari_data_import_client_unittest.mm" ]
+  deps = [
+    ":model",
+    "//components/password_manager/core/browser/import:importer",
+    "//ios/chrome/browser/safari_data_import/public",
+    "//testing/gtest",
+  ]
+}
diff --git a/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.h b/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.h
new file mode 100644
index 0000000..a2b3b1e
--- /dev/null
+++ b/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.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 IOS_CHROME_BROWSER_SAFARI_DATA_IMPORT_MODEL_IOS_SAFARI_DATA_IMPORT_CLIENT_H_
+#define IOS_CHROME_BROWSER_SAFARI_DATA_IMPORT_MODEL_IOS_SAFARI_DATA_IMPORT_CLIENT_H_
+
+#import "base/memory/weak_ptr.h"
+#import "components/user_data_importer/utility/safari_data_import_client.h"
+
+@protocol SafariDataItemConsumer;
+
+// A C++ class that provides a platform-specific implementation for
+// `SafariDataImportClient` on iOS.
+class IOSSafariDataImportClient : public SafariDataImportClient {
+ public:
+  IOSSafariDataImportClient();
+  ~IOSSafariDataImportClient() override;
+
+  // Consumer object handling UI updates to display the progress of data
+  // importing. This needs to be set before preparing the .zip file containing
+  // Safari data.
+  void SetSafariDataItemConsumer(id<SafariDataItemConsumer> consumer);
+
+  // SafariDataImportClient:
+  void OnTotalFailure() override;
+  void OnBookmarksReady(size_t count) override;
+  void OnHistoryReady(size_t estimated_count,
+                      std::vector<std::u16string> profiles) override;
+  void OnPasswordsReady(
+      const password_manager::ImportResults& results) override;
+  void OnPaymentCardsReady(size_t count) override;
+  void OnBookmarksImported(size_t count) override;
+  void OnHistoryImported(size_t count) override;
+  void OnPasswordsImported(
+      const password_manager::ImportResults& results) override;
+  void OnPaymentCardsImported(size_t count) override;
+  base::WeakPtr<SafariDataImportClient> AsWeakPtr() override;
+
+ private:
+  __weak id<SafariDataItemConsumer> consumer_;
+  base::WeakPtrFactory<IOSSafariDataImportClient> weak_factory_{this};
+};
+
+#endif  // IOS_CHROME_BROWSER_SAFARI_DATA_IMPORT_MODEL_IOS_SAFARI_DATA_IMPORT_CLIENT_H_
diff --git a/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.mm b/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.mm
new file mode 100644
index 0000000..92f4412
--- /dev/null
+++ b/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client.mm
@@ -0,0 +1,92 @@
+// 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/safari_data_import/model/ios_safari_data_import_client.h"
+
+#import "base/notreached.h"
+#import "components/password_manager/core/browser/import/import_results.h"
+#import "ios/chrome/browser/safari_data_import/public/safari_data_item.h"
+#import "ios/chrome/browser/safari_data_import/public/safari_data_item_consumer.h"
+
+IOSSafariDataImportClient::IOSSafariDataImportClient() = default;
+IOSSafariDataImportClient::~IOSSafariDataImportClient() = default;
+
+void IOSSafariDataImportClient::SetSafariDataItemConsumer(
+    id<SafariDataItemConsumer> consumer) {
+  consumer_ = consumer;
+}
+
+#pragma mark - IOSSafariDataImportClient
+
+void IOSSafariDataImportClient::OnTotalFailure() {
+  // TODO(crbug.com/420703283): Handle invalid upload.
+}
+
+void IOSSafariDataImportClient::OnBookmarksReady(size_t count) {
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kBookmarks
+                                    status:SafariDataItemImportStatus::kReady
+                                     count:count]];
+}
+
+void IOSSafariDataImportClient::OnHistoryReady(
+    size_t estimated_count,
+    std::vector<std::u16string> profiles) {
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kHistory
+                                    status:SafariDataItemImportStatus::kReady
+                                     count:estimated_count]];
+}
+
+void IOSSafariDataImportClient::OnPasswordsReady(
+    const password_manager::ImportResults& results) {
+  // TODO(crbug.com/420703283): Extrapolate password details.
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kPasswords
+                                    status:SafariDataItemImportStatus::kReady
+                                     count:results.number_to_import]];
+}
+
+void IOSSafariDataImportClient::OnPaymentCardsReady(size_t count) {
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kPayment
+                                    status:SafariDataItemImportStatus::kReady
+                                     count:count]];
+}
+
+void IOSSafariDataImportClient::OnBookmarksImported(size_t count) {
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kBookmarks
+                                    status:SafariDataItemImportStatus::kImported
+                                     count:count]];
+}
+
+void IOSSafariDataImportClient::OnHistoryImported(size_t count) {
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kHistory
+                                    status:SafariDataItemImportStatus::kImported
+                                     count:count]];
+}
+
+void IOSSafariDataImportClient::OnPasswordsImported(
+    const password_manager::ImportResults& results) {
+  // TODO(crbug.com/420703283): Extrapolate password details.
+  SafariDataItem* item =
+      [[SafariDataItem alloc] initWithType:SafariDataItemType::kPasswords
+                                    status:SafariDataItemImportStatus::kImported
+                                     count:results.number_imported];
+  item.invalidCount = static_cast<int>(results.displayed_entries.size());
+  [consumer_ populateItem:item];
+}
+
+void IOSSafariDataImportClient::OnPaymentCardsImported(size_t count) {
+  [consumer_ populateItem:[[SafariDataItem alloc]
+                              initWithType:SafariDataItemType::kPayment
+                                    status:SafariDataItemImportStatus::kImported
+                                     count:count]];
+}
+
+base::WeakPtr<SafariDataImportClient> IOSSafariDataImportClient::AsWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
diff --git a/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client_unittest.mm b/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client_unittest.mm
new file mode 100644
index 0000000..8264d54
--- /dev/null
+++ b/ios/chrome/browser/safari_data_import/model/ios_safari_data_import_client_unittest.mm
@@ -0,0 +1,131 @@
+// 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/safari_data_import/model/ios_safari_data_import_client.h"
+
+#import "components/password_manager/core/browser/import/import_results.h"
+#import "ios/chrome/browser/safari_data_import/public/safari_data_item.h"
+#import "ios/chrome/browser/safari_data_import/public/safari_data_item_consumer.h"
+#import "testing/gtest/include/gtest/gtest.h"
+#import "testing/platform_test.h"
+
+/// A mock SafariDataItemConsumer for use in tests.
+@interface MockSafariDataItemConsumer : NSObject <SafariDataItemConsumer>
+@property(nonatomic, strong) SafariDataItem* lastPopulatedItem;
+@end
+
+@implementation MockSafariDataItemConsumer
+- (void)populateItem:(SafariDataItem*)item {
+  self.lastPopulatedItem = item;
+}
+@end
+
+/// Test fixture for `IOSSafariDataImportClient`.
+class IOSSafariDataImportClientTest : public PlatformTest {
+ protected:
+  IOSSafariDataImportClientTest() {
+    consumer_ = [[MockSafariDataItemConsumer alloc] init];
+    client_.SetSafariDataItemConsumer(consumer_);
+  }
+
+  /// Returns the Safari data import client.
+  IOSSafariDataImportClient* client() { return &client_; }
+
+  /// Returns the last populated item
+  SafariDataItem* last_populated_item() { return consumer_.lastPopulatedItem; }
+
+ private:
+  IOSSafariDataImportClient client_;
+  MockSafariDataItemConsumer* consumer_;
+};
+
+/// Tests that OnBookmarksReady() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnBookmarksReady) {
+  client()->OnBookmarksReady(10);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kBookmarks);
+  EXPECT_EQ(item.count, 10);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kReady);
+}
+
+/// Tests that OnHistoryReady() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnHistoryReady) {
+  client()->OnHistoryReady(20, {});
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kHistory);
+  EXPECT_EQ(item.count, 20);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kReady);
+}
+
+/// Tests that OnPasswordsReady() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnPasswordsReady) {
+  password_manager::ImportResults results;
+  results.number_to_import = 30;
+  client()->OnPasswordsReady(results);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kPasswords);
+  EXPECT_EQ(item.count, 30);
+  EXPECT_EQ(item.invalidCount, 0);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kReady);
+}
+
+/// Tests that OnPaymentCardsReady() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnPaymentCardsReady) {
+  client()->OnPaymentCardsReady(40);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kPayment);
+  EXPECT_EQ(item.count, 40);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kReady);
+}
+
+/// Tests that OnBookmarksImported() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnBookmarksImported) {
+  client()->OnBookmarksImported(10);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kBookmarks);
+  EXPECT_EQ(item.count, 10);
+  EXPECT_EQ(item.invalidCount, 0);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kImported);
+}
+
+/// Tests that OnHistoryImported() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnHistoryImported) {
+  client()->OnHistoryImported(20);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kHistory);
+  EXPECT_EQ(item.count, 20);
+  EXPECT_EQ(item.invalidCount, 0);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kImported);
+}
+
+/// Tests that OnPasswordsImported() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnPasswordsImported) {
+  password_manager::ImportResults results;
+  results.number_imported = 30;
+  results.displayed_entries = {password_manager::ImportEntry()};
+  client()->OnPasswordsImported(results);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kPasswords);
+  EXPECT_EQ(item.count, 30);
+  EXPECT_EQ(item.invalidCount, 1);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kImported);
+}
+
+/// Tests that OnPaymentCardsImported() populates the consumer.
+TEST_F(IOSSafariDataImportClientTest, OnPaymentCardsImported) {
+  client()->OnPaymentCardsImported(40);
+  SafariDataItem* item = last_populated_item();
+  ASSERT_TRUE(item);
+  EXPECT_EQ(item.type, SafariDataItemType::kPayment);
+  EXPECT_EQ(item.count, 40);
+  EXPECT_EQ(item.invalidCount, 0);
+  EXPECT_EQ(item.status, SafariDataItemImportStatus::kImported);
+}
diff --git a/ios/chrome/browser/safari_data_import/public/BUILD.gn b/ios/chrome/browser/safari_data_import/public/BUILD.gn
index c5fdb6e..97f40f5 100644
--- a/ios/chrome/browser/safari_data_import/public/BUILD.gn
+++ b/ios/chrome/browser/safari_data_import/public/BUILD.gn
@@ -11,6 +11,7 @@
     "safari_data_item.mm",
     "safari_data_item_consumer.h",
   ]
+  deps = [ "//base" ]
   frameworks = [ "Foundation.framework" ]
 }
 
diff --git a/ios/chrome/browser/safari_data_import/public/safari_data_item.h b/ios/chrome/browser/safari_data_import/public/safari_data_item.h
index 3c96fec..904f8e0 100644
--- a/ios/chrome/browser/safari_data_import/public/safari_data_item.h
+++ b/ios/chrome/browser/safari_data_import/public/safari_data_item.h
@@ -36,18 +36,23 @@
 /// One of { kReady, kImporting, kImported }.
 @property(nonatomic, readonly) SafariDataItemImportStatus status;
 
-/// Number of items. Should be updated when status transitions to
-/// `kReadyToImport`.
-@property(nonatomic, assign) int count;
+/// Number of items.
+@property(nonatomic, readonly) int count;
 
-/// Number of invalid items; should be updated when status transitions to
-/// `kImported`. Applicable for passwords only; value will be 0 for other types.
+/// Number of invalid items; Applicable for passwords only; value will be 0 for
+/// other types.
 @property(nonatomic, assign) int invalidCount;
 
 /// Initializer with data item type.
-- (instancetype)initWithType:(SafariDataItemType)type NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithType:(SafariDataItemType)type
+                      status:(SafariDataItemImportStatus)status
+                       count:(size_t)count NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
+/// Transition the item to the next import status. Should not be called if the
+/// status is `kImported`.
+- (void)transitionToNextStatus;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_SAFARI_DATA_IMPORT_PUBLIC_SAFARI_DATA_ITEM_H_
diff --git a/ios/chrome/browser/safari_data_import/public/safari_data_item.mm b/ios/chrome/browser/safari_data_import/public/safari_data_item.mm
index 89e1ccfc..c618b3b 100644
--- a/ios/chrome/browser/safari_data_import/public/safari_data_item.mm
+++ b/ios/chrome/browser/safari_data_import/public/safari_data_item.mm
@@ -4,18 +4,39 @@
 
 #import "ios/chrome/browser/safari_data_import/public/safari_data_item.h"
 
+#import "base/check_op.h"
+#import "base/notreached.h"
+
 @implementation SafariDataItem
 
 @synthesize type = _type;
 @synthesize status = _status;
+@synthesize count = _count;
 
-- (instancetype)initWithType:(SafariDataItemType)type {
+- (instancetype)initWithType:(SafariDataItemType)type
+                      status:(SafariDataItemImportStatus)status
+                       count:(size_t)count {
   self = [super init];
   if (self) {
     _type = type;
-    _status = SafariDataItemImportStatus::kReady;
+    _status = status;
+    _count = static_cast<int>(count);
   }
   return self;
 }
 
+- (void)transitionToNextStatus {
+  switch (self.status) {
+    case SafariDataItemImportStatus::kReady:
+      _status = SafariDataItemImportStatus::kImporting;
+      break;
+    case SafariDataItemImportStatus::kImporting:
+      _status = SafariDataItemImportStatus::kImported;
+      break;
+    case SafariDataItemImportStatus::kImported:
+      NOTREACHED() << "item of type " << static_cast<NSUInteger>(self.type)
+                   << " is already imported";
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm b/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm
index 1451d25..ea707b2 100644
--- a/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/legacy_accounts_table_egtest.mm
@@ -487,6 +487,11 @@
 
 // Tests to sign out with a managed account.
 - (void)testSignOutWithManagedAccount {
+  // TODO(crbug.com/433726717): Test disabled on iPhones.
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
+  }
+
   // Sign In `fakeManagedIdentity`.
   FakeSystemIdentity* fakeIdentity = [FakeSystemIdentity fakeManagedIdentity];
   [SigninEarlGrey signinWithFakeManagedIdentityInPersonalProfile:fakeIdentity];
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_coordinator.mm b/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_coordinator.mm
index 7c269fc..05e1482 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_coordinator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_coordinator.mm
@@ -77,7 +77,6 @@
              passwordCheckManager:IOSChromePasswordCheckManagerFactory::
                                       GetForProfile(profile)
                                           .get()
-                      prefService:profile->GetPrefs()
                       syncService:SyncServiceFactory::GetForProfile(profile)
       passwordRequirementsService:IOSPasswordRequirementsServiceFactory::
                                       GetForProfile(profile)];
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.h b/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.h
index ada1cf9..d25105c 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.h
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.h
@@ -12,7 +12,6 @@
 @protocol AddPasswordDetailsConsumer;
 @protocol AddPasswordMediatorDelegate;
 class IOSChromePasswordCheckManager;
-class PrefService;
 
 namespace syncer {
 class SyncService;
@@ -27,7 +26,6 @@
 
 - (instancetype)initWithDelegate:(id<AddPasswordMediatorDelegate>)delegate
             passwordCheckManager:(IOSChromePasswordCheckManager*)manager
-                     prefService:(PrefService*)prefService
                      syncService:(syncer::SyncService*)syncService
      passwordRequirementsService:
          (password_manager::PasswordRequirementsService*)
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.mm b/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.mm
index ff914ff..6adc73e 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_details/add_password_mediator.mm
@@ -61,8 +61,6 @@
 @interface AddPasswordMediator () <AddPasswordViewControllerDelegate> {
   // Password Check manager.
   raw_ptr<IOSChromePasswordCheckManager> _manager;
-  // Pref service.
-  raw_ptr<PrefService> _prefService;
   // Sync service.
   raw_ptr<syncer::SyncService> _syncService;
   // Used to create and run validation tasks.
@@ -89,20 +87,17 @@
 
 - (instancetype)initWithDelegate:(id<AddPasswordMediatorDelegate>)delegate
             passwordCheckManager:(IOSChromePasswordCheckManager*)manager
-                     prefService:(PrefService*)prefService
                      syncService:(syncer::SyncService*)syncService
      passwordRequirementsService:
          (password_manager::PasswordRequirementsService*)
              passwordRequirementsService {
   DCHECK(delegate);
   DCHECK(manager);
-  DCHECK(prefService);
   DCHECK(syncService);
   self = [super init];
   if (self) {
     _delegate = delegate;
     _manager = manager;
-    _prefService = prefService;
     _syncService = syncService;
     _passwordRequirementsService = passwordRequirementsService;
     _sequencedTaskRunner = base::ThreadPool::CreateSequencedTaskRunner(
@@ -118,8 +113,7 @@
   }
   _consumer = consumer;
   std::optional<std::string> account =
-      password_manager::sync_util::GetAccountForSaving(_prefService,
-                                                       _syncService);
+      password_manager::sync_util::GetAccountForSaving(_syncService);
   if (account) {
     CHECK(!account->empty());
     [_consumer setAccountSavingPasswords:SysUTF8ToNSString(*account)];
@@ -161,8 +155,7 @@
 
   credential.note = SysNSStringToUTF16(note);
   credential.stored_in = {
-      password_manager::features_util::IsAccountStorageEnabled(_prefService,
-                                                               _syncService)
+      password_manager::features_util::IsAccountStorageEnabled(_syncService)
           ? password_manager::PasswordForm::Store::kAccountStore
           : password_manager::PasswordForm::Store::kProfileStore};
 
@@ -233,8 +226,7 @@
 - (BOOL)shouldShowSuggestPasswordItem {
   // Only show the field `suggestPasswordItem` to user who are signed in and
   // syncing password to their Google Account.
-  return password_manager::features_util::IsAccountStorageEnabled(_prefService,
-                                                                  _syncService);
+  return password_manager::features_util::IsAccountStorageEnabled(_syncService);
 }
 
 // Requests a generated password and calls the completion block with the result.
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_mediator.mm b/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_mediator.mm
index e3680bc..2fc48425 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_mediator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_details/password_details_mediator.mm
@@ -573,7 +573,7 @@
     credentialDetails.shouldOfferToMoveToAccount =
         self.context == DetailsContext::kPasswordSettings &&
         password_manager::features_util::IsAccountStorageEnabled(
-            _prefService, _syncService) &&
+            _syncService) &&
         ShouldShowLocalOnlyIcon(credential, _syncService);
     [passwords addObject:credentialDetails];
   }
@@ -632,8 +632,7 @@
   }
 #endif  // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
-  return password_manager::features_util::IsAccountStorageEnabled(_prefService,
-                                                                  _syncService);
+  return password_manager::features_util::IsAccountStorageEnabled(_syncService);
 }
 
 @end
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller_unittest.mm b/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller_unittest.mm
index cebeba2f..6f4d47a 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller_unittest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_manager_view_controller_unittest.mm
@@ -115,8 +115,8 @@
                                          GetForProfile(profile)
                        faviconLoader:IOSChromeFaviconLoaderFactory::
                                          GetForProfile(profile)
-                         syncService:SyncServiceFactory::GetForProfile(profile)
-                         prefService:profile->GetPrefs()];
+                         syncService:SyncServiceFactory::GetForProfile(
+                                         profile)];
 
     // Inject some fake passwords to pass the loading state.
     PasswordManagerViewController* passwords_controller =
diff --git a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_mediator.mm b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_mediator.mm
index b2e5f24..e523304f 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_mediator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/password_settings/password_settings_mediator.mm
@@ -451,8 +451,7 @@
 // Computes the amount of local passwords and passes that on to the consumer.
 - (void)updateShowBulkMovePasswordsToAccount {
   [self.consumer setCanBulkMove:password_manager::features_util::
-                                    IsAccountStorageEnabled(_prefService,
-                                                            _syncService)
+                                    IsAccountStorageEnabled(_syncService)
             localPasswordsCount:[self computeLocalPasswordsCount]];
 }
 
diff --git a/ios/chrome/browser/settings/ui_bundled/password/passwords_coordinator.mm b/ios/chrome/browser/settings/ui_bundled/password/passwords_coordinator.mm
index bcf0194..c3ad518d 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/passwords_coordinator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/passwords_coordinator.mm
@@ -147,8 +147,7 @@
       initWithPasswordCheckManager:IOSChromePasswordCheckManagerFactory::
                                        GetForProfile(profile)
                      faviconLoader:faviconLoader
-                       syncService:SyncServiceFactory::GetForProfile(profile)
-                       prefService:profile->GetPrefs()];
+                       syncService:SyncServiceFactory::GetForProfile(profile)];
   self.mediator.tracker =
       feature_engagement::TrackerFactory::GetForProfile(profile);
 
diff --git a/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.h b/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.h
index 2b13e3d..f80bb3a 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.h
+++ b/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.h
@@ -15,7 +15,6 @@
 class FaviconLoader;
 class IOSChromePasswordCheckManager;
 @protocol PasswordsConsumer;
-class PrefService;
 
 namespace syncer {
 class SyncService;
@@ -35,7 +34,6 @@
                         passwordCheckManager
                                faviconLoader:(FaviconLoader*)faviconLoader
                                  syncService:(syncer::SyncService*)syncService
-                                 prefService:(PrefService*)prefService
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.mm b/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.mm
index ae0cd7f2..eb1ca77 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator.mm
@@ -101,21 +101,16 @@
 
   // Service to know whether passwords are synced.
   raw_ptr<syncer::SyncService> _syncService;
-
-  // The user pref service.
-  raw_ptr<PrefService> _prefService;
 }
 
 - (instancetype)initWithPasswordCheckManager:
                     (scoped_refptr<IOSChromePasswordCheckManager>)
                         passwordCheckManager
                                faviconLoader:(FaviconLoader*)faviconLoader
-                                 syncService:(syncer::SyncService*)syncService
-                                 prefService:(PrefService*)prefService {
+                                 syncService:(syncer::SyncService*)syncService {
   self = [super init];
   if (self) {
     _syncService = syncService;
-    _prefService = prefService;
     _faviconLoader = faviconLoader;
 
     _syncObserver = std::make_unique<SyncObserverBridge>(self, syncService);
@@ -164,7 +159,6 @@
   _passwordCheckManager.reset();
   _savedPasswordsPresenter = nullptr;
   _faviconLoader = nullptr;
-  _prefService = nullptr;
   _syncService = nullptr;
 }
 
@@ -366,7 +360,7 @@
 // Compute whether user is capable to run password check in Google Account.
 - (BOOL)canUseAccountPasswordCheckup {
   return password_manager::features_util::IsAccountStorageEnabled(
-             _prefService, _syncService) &&
+             _syncService) &&
          !_syncService->GetUserSettings()->IsEncryptEverythingEnabled();
 }
 
diff --git a/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator_unittest.mm b/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator_unittest.mm
index b33d03d..391f928 100644
--- a/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator_unittest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/password/passwords_mediator_unittest.mm
@@ -168,8 +168,7 @@
         initWithPasswordCheckManager:password_check_
                        faviconLoader:IOSChromeFaviconLoaderFactory::
                                          GetForProfile(profile_.get())
-                         syncService:&sync_service_
-                         prefService:profile_->GetPrefs()];
+                         syncService:&sync_service_];
 
     mock_tracker_ = static_cast<feature_engagement::test::MockTracker*>(
         feature_engagement::TrackerFactory::GetForProfile(profile()));
diff --git a/ios/chrome/browser/settings/ui_bundled/safety_check/safety_check_mediator.mm b/ios/chrome/browser/settings/ui_bundled/safety_check/safety_check_mediator.mm
index 89b19b83..6d32c0b 100644
--- a/ios/chrome/browser/settings/ui_bundled/safety_check/safety_check_mediator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/safety_check/safety_check_mediator.mm
@@ -785,7 +785,7 @@
 // Computes whether user is capable to run password check in Google Account.
 - (BOOL)canUseAccountPasswordCheckup {
   return password_manager::features_util::IsAccountStorageEnabled(
-             self.userPrefService, self.syncService) &&
+             self.syncService) &&
          !self.syncService->GetUserSettings()->IsEncryptEverythingEnabled();
 }
 
diff --git a/ios/chrome/browser/share_kit/ui/BUILD.gn b/ios/chrome/browser/share_kit/ui/BUILD.gn
deleted file mode 100644
index 1d5c50a..0000000
--- a/ios/chrome/browser/share_kit/ui/BUILD.gn
+++ /dev/null
@@ -1,15 +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.
-
-source_set("ui") {
-  sources = [
-    "share_kit_errors_alert_util.h",
-    "share_kit_errors_alert_util.mm",
-  ]
-  deps = [
-    "//base",
-    "//ios/chrome/app/strings",
-    "//ui/base",
-  ]
-}
diff --git a/ios/chrome/browser/share_kit/ui/OWNERS b/ios/chrome/browser/share_kit/ui/OWNERS
deleted file mode 100644
index 9132da8..0000000
--- a/ios/chrome/browser/share_kit/ui/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-ewannpv@chromium.org
diff --git a/ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.h b/ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.h
deleted file mode 100644
index b223487..0000000
--- a/ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_SHARE_KIT_UI_SHARE_KIT_ERRORS_ALERT_UTIL_H_
-#define IOS_CHROME_BROWSER_SHARE_KIT_UI_SHARE_KIT_ERRORS_ALERT_UTIL_H_
-
-#import <UIKit/UIKit.h>
-
-namespace share_kit {
-
-// Returns the alert displayed when the shared link is invalid.
-UIAlertController* InvalidLinkAlert();
-
-}  // namespace share_kit
-
-#endif  // IOS_CHROME_BROWSER_SHARE_KIT_UI_SHARE_KIT_ERRORS_ALERT_UTIL_H_
diff --git a/ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.mm b/ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.mm
deleted file mode 100644
index 342c73d..0000000
--- a/ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.mm
+++ /dev/null
@@ -1,44 +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 "ios/chrome/browser/share_kit/ui/share_kit_errors_alert_util.h"
-
-#import "base/strings/sys_string_conversions.h"
-#import "ios/chrome/grit/ios_strings.h"
-#import "ui/base/l10n/l10n_util.h"
-
-namespace share_kit {
-
-namespace {
-
-// Returns an UIAlertController for the given parameters.
-UIAlertController* ConfigureAlertController(
-    int title,
-    int message,
-    int action_title,
-    void (^action_handler)(UIAlertAction*)) {
-  UIAlertController* alert = [UIAlertController
-      alertControllerWithTitle:l10n_util::GetNSString(title)
-                       message:l10n_util::GetNSString(message)
-                preferredStyle:UIAlertControllerStyleAlert];
-
-  UIAlertAction* action =
-      [UIAlertAction actionWithTitle:l10n_util::GetNSString(action_title)
-                               style:UIAlertActionStyleDefault
-                             handler:action_handler];
-  [alert addAction:action];
-  return alert;
-}
-
-}  // namespace
-
-UIAlertController* InvalidLinkAlert() {
-  return ConfigureAlertController(
-      IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_TITLE,
-      IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_MESSAGE,
-      IDS_IOS_SHARE_KIT_JOIN_ALERT_EXPIRED_ACTION_TITLE,
-      /*action_handler*/ nil);
-}
-
-}  // namespace share_kit
diff --git a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
index 897654e..2d3b622e 100644
--- a/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
+++ b/ios/chrome/browser/shared/coordinator/scene/scene_controller.mm
@@ -61,6 +61,7 @@
 #import "ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_coordinator_delegate.h"
 #import "ios/chrome/browser/authentication/ui_bundled/change_profile/change_profile_authentication_continuation.h"
 #import "ios/chrome/browser/authentication/ui_bundled/change_profile/change_profile_load_url.h"
+#import "ios/chrome/browser/authentication/ui_bundled/change_profile/change_profile_signout_continuation.h"
 #import "ios/chrome/browser/authentication/ui_bundled/continuation.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/features.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/promo/signin_fullscreen_promo_scene_agent.h"
@@ -179,6 +180,7 @@
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.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/authentication_service_observer_bridge.h"
 #import "ios/chrome/browser/signin/model/chrome_account_manager_service.h"
 #import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/signin/model/constants.h"
@@ -270,9 +272,6 @@
 // The App Store page for Google Chrome.
 NSString* const kChromeAppStoreURL = @"https://apps.apple.com/app/id535886823";
 
-// String passed in the URL context to request to open it in a sign-out state.
-NSString* const kNoAccountId = @"No account";
-
 // Enum for IOS.NumberOfContextsToOpen histogram.
 // Keep in sync with "ContextsToOpen" in tools/metrics/histograms/enums.xml.
 enum class ContextsToOpen {
@@ -401,6 +400,7 @@
 // TODO(crbug.com/429354805): Add method comments(!)
 
 @interface SceneController () <AccountMenuCoordinatorDelegate,
+                               AuthenticationServiceObserving,
                                HistoryCoordinatorDelegate,
                                IncognitoInterstitialCoordinatorDelegate,
                                PasswordCheckupCoordinatorDelegate,
@@ -449,6 +449,9 @@
   // This is used to ensure that the image search is only triggered when the BVC
   // is active.
   NSData* _imageSearchData;
+  // Observer for auth service status changes.
+  std::unique_ptr<AuthenticationServiceObserverBridge>
+      _authServiceObserverBridge;
 }
 
 // Navigation View controller for the settings.
@@ -532,6 +535,9 @@
 @property(nonatomic, strong)
     YoutubeIncognitoCoordinator* youtubeIncognitoCoordinator;
 
+// The profile of the current scene.
+@property(nonatomic, readonly) ProfileIOS* profile;
+
 @end
 
 @implementation SceneController
@@ -590,6 +596,10 @@
   return self.browserViewWrangler.mainInterface;
 }
 
+- (ProfileIOS*)profile {
+  return self.sceneState.profileState.profile;
+}
+
 - (WrangledBrowser*)currentInterface {
   return self.browserViewWrangler.currentInterface;
 }
@@ -869,6 +879,39 @@
 
 #pragma mark - private
 
+// If sign-in is disabled, switch to the personal profile and sign-out.
+- (void)signoutIfNeeded {
+  AuthenticationService* authenticationService =
+      AuthenticationServiceFactory::GetForProfile(
+          self.sceneState.profileState.profile);
+  if (authenticationService->SigninEnabled()) {
+    return;
+  }
+  // If sign-in is disabled, switch to personal profile and sign-out.
+  ProfileIOS* profile = self.sceneState.profileState.profile;
+  const std::string& profileName = profile->GetProfileName();
+  BOOL isPersonalProfile = GetApplicationContext()
+                               ->GetProfileManager()
+                               ->GetProfileAttributesStorage()
+                               ->GetPersonalProfileName() == profileName;
+  if (!isPersonalProfile) {
+    auto signoutSource = signin_metrics::ProfileSignout::kPrefChanged;
+    ChangeProfileContinuation continuation =
+        CreateChangeProfileSignoutContinuation(
+            signoutSource, /*force_snackbar_over_toolbar=*/false,
+            /*should_record_metrics=*/false, /*snackbar_message =*/nil,
+            base::DoNothing());
+    signin::SwitchToPersonalProfile(self.sceneState,
+                                    ChangeProfileReason::kManagedAccountSignOut,
+                                    std::move(continuation));
+    return;
+  }
+  if (![self isSignedIn]) {
+    authenticationService->SignOut(signin_metrics::ProfileSignout::kPrefChanged,
+                                   nil);
+  }
+}
+
 - (void)stopAccountMenu {
   [_accountMenuCoordinator stop];
   _accountMenuCoordinator.delegate = nil;
@@ -910,7 +953,7 @@
 
       std::optional<std::string> profileName;
 
-      if ([context.gaiaID isEqualToString:kNoAccountId]) {
+      if ([context.gaiaID isEqualToString:app_group::kNoAccount]) {
         // Use the personal profile name if there is no GaiaID (this happens in
         // the sign-out scenario).
         profileName = GetApplicationContext()
@@ -991,8 +1034,7 @@
     NSString* newGaiaID = base::SysUTF8ToNSString(newGaia);
 
     AuthenticationService* authService =
-        AuthenticationServiceFactory::GetForProfile(
-            self.sceneState.profileState.profile);
+        AuthenticationServiceFactory::GetForProfile(self.profile);
     id<SystemIdentity> identityOnDevice =
         authService->GetPrimaryIdentity(signin::ConsentLevel::kSignin);
     gaiaInApp = identityOnDevice.gaiaID;
@@ -1003,14 +1045,14 @@
       continue;
     }
 
-    if ([newGaiaID isEqualToString:kNoAccountId] && gaiaInApp) {
+    if ([newGaiaID isEqualToString:app_group::kNoAccount] && gaiaInApp) {
       return
           [[WidgetContext alloc] initWithContext:context
                                           gaiaID:newGaiaID
                                             type:AccountSwitchType::kSignOut];
     }
     if (![newGaiaID isEqualToString:gaiaInApp] &&
-        ![newGaiaID isEqualToString:kNoAccountId]) {
+        ![newGaiaID isEqualToString:app_group::kNoAccount]) {
       return [[WidgetContext alloc] initWithContext:context
                                              gaiaID:newGaiaID
                                                type:AccountSwitchType::kSignIn];
@@ -1174,6 +1216,16 @@
       [applicationHandler openURLInNewTab:command];
       [self finishActivatingBrowserDismissingTabSwitcher];
     }
+
+    AuthenticationService* authenticationService =
+        AuthenticationServiceFactory::GetForProfile(
+            self.sceneState.profileState.profile);
+    _authServiceObserverBridge =
+        std::make_unique<AuthenticationServiceObserverBridge>(
+            authenticationService, self);
+    // The user may be signed-in while sign-in is disabled. In which case,
+    // we must sign the user out, potentially switching profile.
+    [self signoutIfNeeded];
   }
   if (level == SceneActivationLevelBackground) {
     [self recordWindowCreationForSceneState:self.sceneState];
@@ -1193,10 +1245,10 @@
 - (void)startUpChromeUI {
   DCHECK(!self.browserViewWrangler);
   DCHECK(_sceneURLLoadingService.get());
-  DCHECK(self.sceneState.profileState.profile);
+  DCHECK(self.profile);
 
   SceneState* sceneState = self.sceneState;
-  ProfileIOS* profile = sceneState.profileState.profile;
+  ProfileIOS* profile = self.profile;
 
   self.browserViewWrangler =
       [[BrowserViewWrangler alloc] initWithProfile:profile
@@ -1489,6 +1541,7 @@
 
   _incognitoWebStateObserver.reset();
   _mainWebStateObserver.reset();
+  _authServiceObserverBridge.reset();
   _policyWatcherObserver.reset();
 
   // TODO(crbug.com/40778288): Consider moving this at the beginning of
@@ -1515,7 +1568,7 @@
   Browser* browser = self.currentInterface.browser;
   DCHECK(browser);
 
-  if (browser->GetProfile()->IsOffTheRecord()) {
+  if (self.profile->IsOffTheRecord()) {
     return nil;
   }
   web::WebState* webState = browser->GetWebStateList()->GetActiveWebState();
@@ -1630,10 +1683,8 @@
   if (![self isTabAvailableToPresentViewController]) {
     return NO;
   }
-  if (!signin::ShouldPresentUserSigninUpgrade(
-          self.sceneState.browserProviderInterface.mainBrowserProvider.browser
-              ->GetProfile(),
-          version_info::GetVersion())) {
+  if (!signin::ShouldPresentUserSigninUpgrade(self.profile,
+                                              version_info::GetVersion())) {
     return NO;
   }
   // Don't show the promo in Incognito mode.
@@ -1700,9 +1751,7 @@
 
 - (BOOL)isSignedIn {
   AuthenticationService* authenticationService =
-      AuthenticationServiceFactory::GetForProfile(
-          self.sceneState.browserProviderInterface.mainBrowserProvider.browser
-              ->GetProfile());
+      AuthenticationServiceFactory::GetForProfile(self.profile);
   DCHECK(authenticationService);
   DCHECK(authenticationService->initialized());
 
@@ -2226,8 +2275,7 @@
   id<SettingsCommands> settingsHandler =
       HandlerForProtocol(dispatcher, SettingsCommands);
   SigninNotificationInfoBarDelegate::Create(
-      infoBarManager, self.mainInterface.browser->GetProfile(), settingsHandler,
-      baseViewController);
+      infoBarManager, self.profile, settingsHandler, baseViewController);
 }
 
 - (void)setIncognitoContentVisible:(BOOL)incognitoContentVisible {
@@ -2261,8 +2309,7 @@
   Browser* browser = self.mainInterface.browser;
   if (browser) {
     feature_engagement::Tracker* tracker =
-        feature_engagement::TrackerFactory::GetForProfile(
-            browser->GetProfile());
+        feature_engagement::TrackerFactory::GetForProfile(self.profile);
     if (tracker) {
       hasDefaultBrowserBlueDot =
           ShouldTriggerDefaultBrowserHighlightFeature(tracker);
@@ -2339,7 +2386,7 @@
       [[UISceneActivationRequestOptions alloc] init];
   options.requestingScene = self.sceneState.scene;
 
-  ProfileIOS* profile = self.sceneState.profileState.profile;
+  ProfileIOS* profile = self.profile;
   if (profile) {
     AttachProfileNameToActivity(userActivity, profile->GetProfileName());
   }
@@ -3166,7 +3213,7 @@
     return;
   }
   feature_engagement::Tracker* tracker =
-      feature_engagement::TrackerFactory::GetForProfile(browser->GetProfile());
+      feature_engagement::TrackerFactory::GetForProfile(self.profile);
   if (tracker) {
     tracker->NotifyEvent(
         feature_engagement::events::kPasswordManagerWidgetPromoUsed);
@@ -3944,9 +3991,7 @@
     (SigninCoordinatorCompletionCallback)completion {
   DCHECK(self.signinCoordinator);
   AuthenticationService* authenticationService =
-      AuthenticationServiceFactory::GetForProfile(
-          self.sceneState.browserProviderInterface.mainBrowserProvider.browser
-              ->GetProfile());
+      AuthenticationServiceFactory::GetForProfile(self.profile);
   AuthenticationService::ServiceStatus statusService =
       authenticationService->GetServiceStatus();
   switch (statusService) {
@@ -4250,13 +4295,8 @@
 // Clears incognito data that is specific to iOS and won't be cleared by
 // deleting the profile.
 - (void)clearIOSSpecificIncognitoData {
-  DCHECK(self.sceneState.browserProviderInterface.mainBrowserProvider.browser
-             ->GetProfile()
-             ->HasOffTheRecordProfile());
-  ProfileIOS* otrProfile =
-      self.sceneState.browserProviderInterface.mainBrowserProvider.browser
-          ->GetProfile()
-          ->GetOffTheRecordProfile();
+  DCHECK(self.profile->HasOffTheRecordProfile());
+  ProfileIOS* otrProfile = self.profile->GetOffTheRecordProfile();
 
   __weak SceneController* weakSelf = self;
   BrowsingDataRemover* browsingDataRemover =
@@ -4363,8 +4403,7 @@
 // closed (i.e. if there are other incognito tabs open in another Scene, the
 // Profile must not be destroyed).
 - (BOOL)shouldDestroyAndRebuildIncognitoProfile {
-  ProfileIOS* profile = self.sceneState.browserProviderInterface
-                            .mainBrowserProvider.browser->GetProfile();
+  ProfileIOS* profile = self.profile;
   if (!profile->HasOffTheRecordProfile()) {
     return NO;
   }
@@ -4395,8 +4434,7 @@
 
   [self clearIOSSpecificIncognitoData];
 
-  ProfileIOS* profile = self.sceneState.browserProviderInterface
-                            .mainBrowserProvider.browser->GetProfile();
+  ProfileIOS* profile = self.profile;
   DCHECK(profile->HasOffTheRecordProfile());
   ProfileIOS* otrProfile = profile->GetOffTheRecordProfile();
 
@@ -4524,4 +4562,10 @@
   _safariImportCoordinator = nil;
 }
 
+#pragma mark - AuthenticationServiceObserving
+
+- (void)onServiceStatusChanged {
+  [self signoutIfNeeded];
+}
+
 @end
diff --git a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
index a73784f..78e4d9a 100644
--- a/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/shared/model/prefs/browser_prefs.mm
@@ -888,6 +888,16 @@
   // Preferences related to download restrictions enterprise policy.
   registry->RegisterIntegerPref(policy::policy_prefs::kDownloadRestrictions, 0);
 
+  // Preferences related to enterprise cloud profile reporting.
+  registry->RegisterBooleanPref(
+      enterprise_reporting::kCloudProfileReportingEnabled, false);
+  registry->RegisterTimePref(enterprise_reporting::kLastUploadTimestamp,
+                             base::Time());
+  registry->RegisterTimePref(
+      enterprise_reporting::kLastUploadSucceededTimestamp, base::Time());
+  registry->RegisterTimeDeltaPref(
+      enterprise_reporting::kCloudReportingUploadFrequency, base::Hours(24));
+
   // Preferences related to parcel tracking.
   // Deprecated 03/2025.
   registry->RegisterBooleanPref(kIosParcelTrackingOptInPromptDisplayLimitMet,
diff --git a/ios/chrome/browser/shared/ui/animated_promo/BUILD.gn b/ios/chrome/browser/shared/ui/animated_promo/BUILD.gn
new file mode 100644
index 0000000..a3733e3
--- /dev/null
+++ b/ios/chrome/browser/shared/ui/animated_promo/BUILD.gn
@@ -0,0 +1,22 @@
+# 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.
+
+source_set("animated_promo") {
+  sources = [
+    "animated_promo_view_controller.h",
+    "animated_promo_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/shared/ui/util",
+    "//ios/chrome/common/ui/colors",
+    "//ios/chrome/common/ui/confirmation_alert",
+    "//ios/chrome/common/ui/instruction_view",
+    "//ios/chrome/common/ui/promo_style",
+    "//ios/chrome/common/ui/promo_style:utils",
+    "//ios/chrome/common/ui/util",
+    "//ios/public/provider/chrome/browser/lottie:lottie_animation_api",
+  ]
+  frameworks = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h b/ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h
similarity index 80%
rename from ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h
rename to ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h
index e9bb730..c880601 100644
--- a/ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h
+++ b/ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h
@@ -2,14 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_TIPS_NOTIFICATIONS_UI_ANIMATED_PROMO_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_TIPS_NOTIFICATIONS_UI_ANIMATED_PROMO_VIEW_CONTROLLER_H_
+#ifndef IOS_CHROME_BROWSER_SHARED_UI_ANIMATED_PROMO_ANIMATED_PROMO_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_SHARED_UI_ANIMATED_PROMO_ANIMATED_PROMO_VIEW_CONTROLLER_H_
 
 #import <UIKit/UIKit.h>
 
 #import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_action_handler.h"
 
-// Container view controller for a full-screen, animated promo.
+// Container view controller for a full-screen promo with a Lottie animation. If
+// the height of the current size class is "regular", the top part of the view
+// plays the animation, and the bottom part displays a
+// `ConfirmationAlertViewController`.
 @interface AnimatedPromoViewController : UIViewController
 
 // The action handler for interactions in this view controller.
@@ -53,4 +56,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_TIPS_NOTIFICATIONS_UI_ANIMATED_PROMO_VIEW_CONTROLLER_H_
+#endif  // IOS_CHROME_BROWSER_SHARED_UI_ANIMATED_PROMO_ANIMATED_PROMO_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.mm b/ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.mm
similarity index 93%
rename from ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.mm
rename to ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.mm
index 963603e..bab2a03 100644
--- a/ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.mm
+++ b/ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.mm
@@ -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 "ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h"
+#import "ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h"
 
 #import "base/check.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
@@ -96,27 +96,12 @@
   [self configureAlertScreen];
   [self layoutAlertScreen];
 
-  if (@available(iOS 17, *)) {
-    NSArray<UITrait>* traits = TraitCollectionSetForTraits(
-        @[ UITraitVerticalSizeClass.class, UITraitUserInterfaceStyle.class ]);
-    [self registerForTraitChanges:traits
-                       withAction:@selector(updateUIOnTraitChange)];
-  }
+  NSArray<UITrait>* traits = TraitCollectionSetForTraits(
+      @[ UITraitVerticalSizeClass.class, UITraitUserInterfaceStyle.class ]);
+  [self registerForTraitChanges:traits
+                     withAction:@selector(updateUIOnTraitChange)];
 }
 
-#if !defined(__IPHONE_17_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_17_0
-// Called when the device is rotated or dark mode is enabled/disabled. (Un)Hide
-// the animations accordingly.
-- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
-  [super traitCollectionDidChange:previousTraitCollection];
-  if (@available(iOS 17, *)) {
-    return;
-  }
-
-  [self updateUIOnTraitChange];
-}
-#endif
-
 #pragma mark - Private
 
 // Helper to determine if any navigation bar is currently visible.
diff --git a/ios/chrome/browser/signin/model/system_account_updater.mm b/ios/chrome/browser/signin/model/system_account_updater.mm
index c26e99d..81f6825 100644
--- a/ios/chrome/browser/signin/model/system_account_updater.mm
+++ b/ios/chrome/browser/signin/model/system_account_updater.mm
@@ -199,7 +199,8 @@
     NSMutableDictionary* updated_dates = [NSMutableDictionary dictionary];
 
     for (NSString* gaia in urls_info) {
-      if (accounts[gaia] || [gaia isEqualToString:app_group::kDefaultAccount]) {
+      if (accounts[gaia] || [gaia isEqualToString:app_group::kNoAccount] ||
+          [gaia isEqualToString:app_group::kDefault]) {
         updated_urls[gaia] = urls_info[gaia];
         updated_dates[gaia] = last_modification_dates_info[gaia];
       }
diff --git a/ios/chrome/browser/signin/model/system_account_updater_unittests.mm b/ios/chrome/browser/signin/model/system_account_updater_unittests.mm
index 73380dc..2718f75 100644
--- a/ios/chrome/browser/signin/model/system_account_updater_unittests.mm
+++ b/ios/chrome/browser/signin/model/system_account_updater_unittests.mm
@@ -113,7 +113,8 @@
   // Add fake data about fakeIdentity1 to kSuggestedItemsForMultiprofile.
   NSMutableDictionary* fake_info = [NSMutableDictionary dictionary];
   [fake_info setObject:@"test_info" forKey:fake_identity.gaiaID];
-  [fake_info setObject:@"test_info" forKey:app_group::kDefaultAccount];
+  [fake_info setObject:@"test_info" forKey:app_group::kDefault];
+  [fake_info setObject:@"test_info" forKey:app_group::kNoAccount];
 
   [shared_defaults setObject:fake_info
                       forKey:app_group::kSuggestedItemsForMultiprofile];
@@ -135,7 +136,8 @@
   {
     NSDictionary* items = [shared_defaults
         objectForKey:app_group::kSuggestedItemsForMultiprofile];
-    EXPECT_TRUE([[items allKeys] containsObject:app_group::kDefaultAccount]);
+    EXPECT_TRUE([[items allKeys] containsObject:app_group::kDefault]);
+    EXPECT_TRUE([[items allKeys] containsObject:app_group::kNoAccount]);
     EXPECT_FALSE([[items allKeys] containsObject:fake_identity.gaiaID]);
   }
 }
@@ -156,7 +158,8 @@
   // Add fake data about fakeIdentity1 to kSuggestedItemsForMultiprofile.
   NSMutableDictionary* fake_info = [NSMutableDictionary dictionary];
   [fake_info setObject:@"test_info" forKey:fake_identity.gaiaID];
-  [fake_info setObject:@"test_info" forKey:app_group::kDefaultAccount];
+  [fake_info setObject:@"test_info" forKey:app_group::kDefault];
+  [fake_info setObject:@"test_info" forKey:app_group::kNoAccount];
 
   [shared_defaults setObject:fake_info
                       forKey:app_group::kSuggestedItemsForMultiprofile];
@@ -180,7 +183,8 @@
     NSDictionary* items = [shared_defaults
         objectForKey:app_group::
                          kSuggestedItemsLastModificationDateForMultiprofile];
-    EXPECT_TRUE([[items allKeys] containsObject:app_group::kDefaultAccount]);
+    EXPECT_TRUE([[items allKeys] containsObject:app_group::kDefault]);
+    EXPECT_TRUE([[items allKeys] containsObject:app_group::kNoAccount]);
     EXPECT_FALSE([[items allKeys] containsObject:fake_identity.gaiaID]);
   }
 }
diff --git a/ios/chrome/browser/sync/model/ios_chrome_sync_client.h b/ios/chrome/browser/sync/model/ios_chrome_sync_client.h
index 9af6e70e..987156f 100644
--- a/ios/chrome/browser/sync/model/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/model/ios_chrome_sync_client.h
@@ -51,9 +51,6 @@
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
   syncer::SyncEngineFactory* GetSyncEngineFactory() override;
   bool IsCustomPassphraseAllowed() override;
-  bool IsPasswordSyncAllowed() override;
-  void SetPasswordSyncAllowedChangeCb(
-      const base::RepeatingClosure& cb) override;
   void RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial(
       const syncer::TrustedVaultAutoUpgradeSyntheticFieldTrialGroup& group)
       override;
diff --git a/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
index 4b8de7d..945fe36 100644
--- a/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/model/ios_chrome_sync_client.mm
@@ -92,15 +92,6 @@
   return true;
 }
 
-bool IOSChromeSyncClient::IsPasswordSyncAllowed() {
-  return true;
-}
-
-void IOSChromeSyncClient::SetPasswordSyncAllowedChangeCb(
-    const base::RepeatingClosure& cb) {
-  // IsPasswordSyncAllowed() doesn't change on //ios/chrome.
-}
-
 void IOSChromeSyncClient::RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial(
     const syncer::TrustedVaultAutoUpgradeSyntheticFieldTrialGroup& group) {
   CHECK(group.is_valid());
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm
index a46e068..b6653c3 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_coordinator.mm
@@ -402,6 +402,8 @@
     [_tabGroupsPanelCoordinator stopChildCoordinators];
   }
 
+  [self cancelCollaborationFlows];
+
   [self dismissPopovers];
 
   [self.inactiveTabsCoordinator hide];
@@ -961,6 +963,16 @@
   }
 }
 
+// Cancels all the currently active collaboration flows.
+- (void)cancelCollaborationFlows {
+  collaboration::CollaborationService* collaborationService =
+      collaboration::CollaborationServiceFactory::GetForProfile(
+          self.regularBrowser->GetProfile());
+  if (collaborationService) {
+    collaborationService->CancelAllFlows();
+  }
+}
+
 #pragma mark - ChromeCoordinator
 
 - (void)start {
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm
index e8b46516..9cb594e 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_grid_view_controller.mm
@@ -261,7 +261,7 @@
   if (@available(iOS 17, *)) {
     NSArray<UITrait>* traits = TraitCollectionSetForTraits(nil);
     [self registerForTraitChanges:traits
-                       withAction:@selector(updateConstraitsOnTraitChange)];
+                       withAction:@selector(updateConstraintsOnTraitChange)];
   }
 }
 
@@ -304,7 +304,7 @@
     return;
   }
 
-  [self updateConstraitsOnTraitChange];
+  [self updateConstraintsOnTraitChange];
 }
 #endif
 
@@ -1533,7 +1533,7 @@
   self.topToolbar.pageControl.userInteractionEnabled = NO;
 }
 
-- (void)updateConstraitsOnTraitChange {
+- (void)updateConstraintsOnTraitChange {
   if (IsPinnedTabsEnabled()) {
     [self updatePinnedTabsViewControllerConstraints];
   }
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_view_controller.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_view_controller.mm
index 8e96fa264..eb46157 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_view_controller.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_groups/recent_activity_view_controller.mm
@@ -26,9 +26,7 @@
 
 namespace {
 
-// The size of the close button.
-const CGFloat kButtonImageSize = 28;
-const CGFloat kButtonSize = 44;
+const CGFloat kButtonImageSize = 18;
 
 typedef NSDiffableDataSourceSnapshot<NSString*, RecentActivityLogItem*>
     ActivityLogSnapshot;
@@ -71,31 +69,6 @@
 
   __weak __typeof(self) weakSelf = self;
 
-  // Configure a close button.
-  UIImage* closeImage = SymbolWithPalette(
-      DefaultSymbolWithPointSize(kXMarkCircleFillSymbol, kButtonImageSize), @[
-        [UIColor colorNamed:kCloseButtonColor],
-        [UIColor colorNamed:kSecondaryBackgroundColor]
-      ]);
-  UIButtonConfiguration* closeButtonConfiguration =
-      [UIButtonConfiguration plainButtonConfiguration];
-  closeButtonConfiguration.image = closeImage;
-  UIButton* closeButton = [UIButton
-      buttonWithConfiguration:closeButtonConfiguration
-                primaryAction:[UIAction actionWithHandler:^(UIAction* action) {
-                  [weakSelf didTapCloseButton];
-                }]];
-  closeButton.accessibilityIdentifier = kRecentActivityLogCloseButtonIdentifier;
-  closeButton.translatesAutoresizingMaskIntoConstraints = NO;
-  [closeButton.widthAnchor constraintEqualToConstant:kButtonSize].active = YES;
-
-  // Configure the menu button.
-  UIImage* menuImage = SymbolWithPalette(
-      DefaultSymbolWithPointSize(kEllipsisCircleFillSymbol, kButtonImageSize),
-      @[
-        [UIColor colorNamed:kCloseButtonColor],
-        [UIColor colorNamed:kSecondaryBackgroundColor]
-      ]);
   UIAction* showAllActivity =
       [UIAction actionWithTitle:l10n_util::GetNSString(
                                     IDS_IOS_SHARE_KIT_MANAGE_ACTIVITY_LOG_TITLE)
@@ -106,23 +79,18 @@
                         }];
   UIMenu* menu = [UIMenu menuWithChildren:@[ showAllActivity ]];
 
-  UIButtonConfiguration* menuButtonConfiguration =
-      [UIButtonConfiguration plainButtonConfiguration];
-  menuButtonConfiguration.image = menuImage;
-  UIButton* menuButton =
-      [UIButton buttonWithConfiguration:menuButtonConfiguration
-                          primaryAction:nil];
-  menuButton.menu = menu;
-  menuButton.showsMenuAsPrimaryAction = YES;
-  menuButton.accessibilityIdentifier = kRecentActivityLogMenuButtonIdentifier;
-  menuButton.translatesAutoresizingMaskIntoConstraints = NO;
-  [menuButton.widthAnchor constraintEqualToConstant:kButtonSize].active = YES;
+  self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
+      initWithBarButtonSystemItem:UIBarButtonSystemItemClose
+                           target:self
+                           action:@selector(didTapCloseButton)];
+  self.navigationItem.rightBarButtonItem.accessibilityIdentifier =
+      kRecentActivityLogCloseButtonIdentifier;
 
-  self.navigationItem.rightBarButtonItem =
-      [[UIBarButtonItem alloc] initWithCustomView:closeButton];
-
-  self.navigationItem.leftBarButtonItem =
-      [[UIBarButtonItem alloc] initWithCustomView:menuButton];
+  self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
+      initWithImage:DefaultSymbolWithPointSize(kMenuSymbol, kButtonImageSize)
+               menu:menu];
+  self.navigationItem.leftBarButtonItem.accessibilityIdentifier =
+      kRecentActivityLogMenuButtonIdentifier;
 
   // Configure a table view.
   UITableView* tableView = self.tableView;
diff --git a/ios/chrome/browser/tabs/model/BUILD.gn b/ios/chrome/browser/tabs/model/BUILD.gn
index 94001ce..1c6d515 100644
--- a/ios/chrome/browser/tabs/model/BUILD.gn
+++ b/ios/chrome/browser/tabs/model/BUILD.gn
@@ -68,6 +68,7 @@
     "//ios/chrome/browser/commerce/model/push_notification",
     "//ios/chrome/browser/complex_tasks/model",
     "//ios/chrome/browser/contextual_panel/model",
+    "//ios/chrome/browser/contextual_panel/model:public",
     "//ios/chrome/browser/crash_report/model/breadcrumbs",
     "//ios/chrome/browser/data_sharing/model",
     "//ios/chrome/browser/download/model",
diff --git a/ios/chrome/browser/tips_notifications/ui/BUILD.gn b/ios/chrome/browser/tips_notifications/ui/BUILD.gn
index b68dea648..a46d67c 100644
--- a/ios/chrome/browser/tips_notifications/ui/BUILD.gn
+++ b/ios/chrome/browser/tips_notifications/ui/BUILD.gn
@@ -4,8 +4,6 @@
 
 source_set("shared") {
   sources = [
-    "animated_promo_view_controller.h",
-    "animated_promo_view_controller.mm",
     "instructions_bottom_sheet_view_controller.h",
     "instructions_bottom_sheet_view_controller.mm",
     "tips_promo_view_controller.h",
@@ -14,9 +12,7 @@
   deps = [
     "//base",
     "//ios/chrome/browser/shared/ui/bottom_sheet:bottom_sheet_view_controller",
-    "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/common/ui/colors",
-    "//ios/chrome/common/ui/confirmation_alert",
     "//ios/chrome/common/ui/instruction_view",
     "//ios/chrome/common/ui/promo_style",
     "//ios/chrome/common/ui/promo_style:utils",
@@ -65,8 +61,11 @@
     "search_what_you_see_promo_view_controller.h",
     "search_what_you_see_promo_view_controller.mm",
   ]
-  deps = [
+  public_deps = [
     ":shared",
+    "//ios/chrome/browser/shared/ui/animated_promo",
+  ]
+  deps = [
     "//ios/chrome/app/strings",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/tips_notifications/ui/search_what_you_see_promo_view_controller.h b/ios/chrome/browser/tips_notifications/ui/search_what_you_see_promo_view_controller.h
index a59280e..b252616 100644
--- a/ios/chrome/browser/tips_notifications/ui/search_what_you_see_promo_view_controller.h
+++ b/ios/chrome/browser/tips_notifications/ui/search_what_you_see_promo_view_controller.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_TIPS_NOTIFICATIONS_UI_SEARCH_WHAT_YOU_SEE_PROMO_VIEW_CONTROLLER_H_
 #define IOS_CHROME_BROWSER_TIPS_NOTIFICATIONS_UI_SEARCH_WHAT_YOU_SEE_PROMO_VIEW_CONTROLLER_H_
 
-#import "ios/chrome/browser/tips_notifications/ui/animated_promo_view_controller.h"
+#import "ios/chrome/browser/shared/ui/animated_promo/animated_promo_view_controller.h"
 
 // The view controller for the full-screen Search What You See tip.
 @interface SearchWhatYouSeePromoViewController : AnimatedPromoViewController
diff --git a/ios/chrome/browser/web/model/navigation_egtest.mm b/ios/chrome/browser/web/model/navigation_egtest.mm
index d20173c..c7d7549 100644
--- a/ios/chrome/browser/web/model/navigation_egtest.mm
+++ b/ios/chrome/browser/web/model/navigation_egtest.mm
@@ -634,6 +634,13 @@
 }
 
 - (void)testEdgeSwipe {
+#if !defined(__IPHONE_26_0) || __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_26_0
+  if (iOS26_OR_ABOVE()) {
+    EARL_GREY_TEST_SKIPPED(@"The swipe gesture when running iOS26 simulators "
+                           @"with Xcode 16 is difficult. Skip this edge case.");
+  }
+#endif
+
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
   [ChromeEarlGrey loadURL:self.testServer->GetURL(kSimpleFileBasedTestURL)];
   [ChromeEarlGrey waitForWebStateContainingText:"pony"];
diff --git a/ios/chrome/browser/whats_new/ui/whats_new_screenshot_view_controller.h b/ios/chrome/browser/whats_new/ui/whats_new_screenshot_view_controller.h
index 30905a605..efbebc520 100644
--- a/ios/chrome/browser/whats_new/ui/whats_new_screenshot_view_controller.h
+++ b/ios/chrome/browser/whats_new/ui/whats_new_screenshot_view_controller.h
@@ -15,6 +15,7 @@
 
 // View controller for the screenshot view for What's New feature and chrome
 // tip.
+// TODO(crbug.com/433790827): Subclass from AnimatedPromoViewController.
 @interface WhatsNewScreenshotViewController : UIViewController
 
 - (instancetype)initWithWhatsNewItem:(WhatsNewItem*)item
diff --git a/ios/chrome/common/app_group/app_group_constants.h b/ios/chrome/common/app_group/app_group_constants.h
index 6b09a1c..bb4fe6d4 100644
--- a/ios/chrome/common/app_group/app_group_constants.h
+++ b/ios/chrome/common/app_group/app_group_constants.h
@@ -214,7 +214,10 @@
 extern NSString* const kEmail;
 extern NSString* const kFullName;
 // Key used to save info for widgets when no account is signed-in.
-extern NSString* const kDefaultAccount;
+extern NSString* const kNoAccount;
+// Key used to save info for widgets when used with default account (the same
+// account used in the app).
+extern NSString* const kDefault;
 
 // Supported bundle IDs for opening incognito links in Chrome.
 extern NSString* const kYoutubeBundleID;
diff --git a/ios/chrome/common/app_group/app_group_constants.mm b/ios/chrome/common/app_group/app_group_constants.mm
index da3e339..52f9173 100644
--- a/ios/chrome/common/app_group/app_group_constants.mm
+++ b/ios/chrome/common/app_group/app_group_constants.mm
@@ -102,7 +102,8 @@
 NSString* const kAccountsOnDevice = @"ios.registered_accounts_on_device";
 NSString* const kEmail = @"email";
 NSString* const kFullName = @"fullName";
-NSString* const kDefaultAccount = @"Default";
+NSString* const kNoAccount = @"No account";
+NSString* const kDefault = @"Default";
 
 NSString* const kYoutubeBundleID = @"com.google.ios.youtube";
 
diff --git a/ios/chrome/common/credential_provider/constants.h b/ios/chrome/common/credential_provider/constants.h
index 1ffc86d4..24943a5d 100644
--- a/ios/chrome/common/credential_provider/constants.h
+++ b/ios/chrome/common/credential_provider/constants.h
@@ -56,6 +56,10 @@
 // currently enabled.
 NSString* AppGroupUserDefaulsCredentialProviderPasskeyPRFEnabled();
 
+// Key for the app group user defaults containing whether signal API is
+// currently enabled.
+NSString* AppGroupUserDefaulsCredentialProviderSignalAPIEnabled();
+
 // Key for the app group user defaults indicating if the credentials have been
 // synced with iOS via AuthenticationServices.
 extern NSString* const
diff --git a/ios/chrome/common/credential_provider/constants.mm b/ios/chrome/common/credential_provider/constants.mm
index 253bd82..10b93837 100644
--- a/ios/chrome/common/credential_provider/constants.mm
+++ b/ios/chrome/common/credential_provider/constants.mm
@@ -76,6 +76,11 @@
 NSString* const kUserDefaultsCredentialProviderPasskeyPRFSetting =
     @"kUserDefaultsCredentialProviderPasskeyPRFSetting";
 
+// Used to generate the key for the app group user defaults containing whether
+// signal API is currently enabled.
+NSString* const kUserDefaultsCredentialProviderSignalAPISetting =
+    @"kUserDefaultsCredentialProviderSignalAPISetting";
+
 // Used to generate a unique AppGroupPrefix to differentiate between different
 // versions of Chrome running in the same device.
 NSString* AppGroupPrefix() {
@@ -176,3 +181,8 @@
   return [AppGroupPrefix()
       stringByAppendingString:kUserDefaultsCredentialProviderPasskeyPRFSetting];
 }
+
+NSString* AppGroupUserDefaulsCredentialProviderSignalAPIEnabled() {
+  return [AppGroupPrefix()
+      stringByAppendingString:kUserDefaultsCredentialProviderSignalAPISetting];
+}
diff --git a/ios/chrome/credential_provider_extension/ui/feature_flags.h b/ios/chrome/credential_provider_extension/ui/feature_flags.h
index 2993d2f8..65536bd 100644
--- a/ios/chrome/credential_provider_extension/ui/feature_flags.h
+++ b/ios/chrome/credential_provider_extension/ui/feature_flags.h
@@ -15,6 +15,9 @@
 // Whether passkey PRF support is enabled.
 BOOL IsPasskeyPRFEnabled();
 
+// Whether signal API is enabled.
+BOOL IsSignalAPIEnabled();
+
 // Whether password creation is enabled for this user by preference.
 BOOL IsPasswordCreationUserEnabled();
 
diff --git a/ios/chrome/credential_provider_extension/ui/feature_flags.mm b/ios/chrome/credential_provider_extension/ui/feature_flags.mm
index 7404417..d7d618e 100644
--- a/ios/chrome/credential_provider_extension/ui/feature_flags.mm
+++ b/ios/chrome/credential_provider_extension/ui/feature_flags.mm
@@ -21,6 +21,12 @@
       boolValue];
 }
 
+BOOL IsSignalApiEnabled() {
+  return [[app_group::GetGroupUserDefaults()
+      objectForKey:AppGroupUserDefaulsCredentialProviderSignalAPIEnabled()]
+      boolValue];
+}
+
 BOOL IsPasswordCreationUserEnabled() {
   return [[app_group::GetGroupUserDefaults()
       objectForKey:
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 229826f6..37f1dec 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -417,6 +417,7 @@
     "//ios/chrome/browser/reminder_notifications/ui:unit_tests",
     "//ios/chrome/browser/sad_tab/ui_bundled:unit_tests",
     "//ios/chrome/browser/safari_data_import/coordinator:unit_tests",
+    "//ios/chrome/browser/safari_data_import/model:unit_tests",
     "//ios/chrome/browser/safe_browsing/model:unit_tests",
     "//ios/chrome/browser/safe_browsing/model/tailored_security:unit_tests",
     "//ios/chrome/browser/safe_mode/model:unit_tests",
diff --git a/ios/chrome/test/data/policy/policy_test_bundle_data.filelist b/ios/chrome/test/data/policy/policy_test_bundle_data.filelist
index acab5df..06aac4a72 100644
--- a/ios/chrome/test/data/policy/policy_test_bundle_data.filelist
+++ b/ios/chrome/test/data/policy/policy_test_bundle_data.filelist
@@ -14,6 +14,7 @@
 //ios/chrome/test/data/policy/pref_mapping/ChromeVariations.json
 //ios/chrome/test/data/policy/pref_mapping/CloudManagementEnrollmentToken.json
 //ios/chrome/test/data/policy/pref_mapping/CloudPolicyOverridesPlatformPolicy.json
+//ios/chrome/test/data/policy/pref_mapping/CloudProfileReportingEnabled.json
 //ios/chrome/test/data/policy/pref_mapping/CloudReportingEnabled.json
 //ios/chrome/test/data/policy/pref_mapping/CloudReportingUploadFrequency.json
 //ios/chrome/test/data/policy/pref_mapping/CloudUserPolicyMerge.json
diff --git a/ios/chrome/test/data/policy/pref_mapping/CloudProfileReportingEnabled.json b/ios/chrome/test/data/policy/pref_mapping/CloudProfileReportingEnabled.json
new file mode 100644
index 0000000..3c4d4e3
--- /dev/null
+++ b/ios/chrome/test/data/policy/pref_mapping/CloudProfileReportingEnabled.json
@@ -0,0 +1,19 @@
+[
+  {
+    "os": [
+      "ios"
+    ],
+    "policy_pref_mapping_tests": [
+      {
+        "policies": {
+          "CloudProfileReportingEnabled": true
+        },
+        "prefs": {
+          "enterprise_reporting.chrome_profile_cloud_reporting": {
+            "value": true
+          }
+        }
+      }
+    ]
+  }
+]
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index ee74eb3b..288e87d 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -1453,6 +1453,11 @@
 }
 
 - (void)waitForKeyboardToAppear {
+  // Disable the synchronization due to the infinite spinner. Without this, the
+  // timer waits for the keyboard infinitely although the keyboard is already
+  // visible.
+  ScopedSynchronizationDisabler disabler;
+
   GREYCondition* waitForKeyboard = [GREYCondition
       conditionWithName:@"Wait for keyboard to appear"
                   block:^BOOL {
diff --git a/ios/chrome/test/providers/bwg/test_bwg.mm b/ios/chrome/test/providers/bwg/test_bwg.mm
index c97e681e..a9fb3d21 100644
--- a/ios/chrome/test/providers/bwg/test_bwg.mm
+++ b/ios/chrome/test/providers/bwg/test_bwg.mm
@@ -31,4 +31,7 @@
   return nil;
 }
 
+void CheckGeminiEligibility(AuthenticationService* auth_service,
+                            BWGEligibilityCallback completion) {}
+
 }  // namespace ios::provider
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
index b79b5296..9852ab7 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-80a0900bf638aa9ed49c790e7cc2b5346ec8f030
\ No newline at end of file
+5d52b7527c90688f85e727c212ff3b7326129343
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
index 64b94fc9..77c5b92 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-cbd10029feebc83f30b1a2756e32bda10e4f4ac9
\ No newline at end of file
+a78f1b487fddbdedee4d43c03da9342fe774c9e7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index 671269a4..d5acc99 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-ef4830c9f04a82f39d387a2a049fef3f1bb99d67
\ No newline at end of file
+bf2609e4986518aac1da3b4f828eb858c446fe2d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
index d326492d..9cdcbfc 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-b43449c0051a3a61543bba027d79cc757cf2b0a2
\ No newline at end of file
+17a901a752ca392c6f5b8593bc5688b70b22a87c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 4f01d8a..c91e7ba 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-0aae6e6590000d29d3e702ad21b170db7e04600a
\ No newline at end of file
+216150115cfd73007114d62dd4354c4d6ab6ab57
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
index fdc5894d..c5ae027f 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-b07e08991ace7ce664f8c9bf6ee972e0fd8cb656
\ No newline at end of file
+c8ed7e8e99083121036732ee2198b9baa7abd00b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
index 5126ad2e..cb49aa0 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-6aeead824d0a1ecbc94e0d26478864c659f2594e
\ No newline at end of file
+8ce158591387de46f60cdb89ae594428544796da
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
index b0e36a3..1289db3 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-aaed10528e98e8d9039f6a5fad4bb895ccc93b80
\ No newline at end of file
+8fd1d1cc7bac655960e28f956c894e353d5ba75a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
index 496ca81..2e997140 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-e39acbf5e05457f9ccc2f88326b69a832e14b685
\ No newline at end of file
+e770dd4565e3857bcfedd6dc7425069c8e6daa87
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 1385223..4356485 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-a0908a36e8c7dfc3ee20331895e2f8aaa98fa38d
\ No newline at end of file
+24496e7355dd18e15d5006faf417c5eb09732a43
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index cd8963d..a747f546 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-c40204ba3722328873e9b885c518daa1fa483e9f
\ No newline at end of file
+7440a6cb51766464579c8abedf05f04e420cf8e9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
index 1e48645..8a9df16 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-35cfbd4545a915e69b9d2454feedf28aec1b5e8f
\ No newline at end of file
+4f424c0a46424414fce4ffc20f16375437fdbf3e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index aee3b534..39d6456a 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-89b1d5b8109dec7affb7c512a4b26a39ee7e278d
\ No newline at end of file
+8d7772b5c5d66f51bb4cb022d689e407a6b11501
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 1b8f6f0d..b252810 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-e63ebe0289bda10c786e1ae1865907487378482b
\ No newline at end of file
+4dc57da753a930e8a762eb20b82f3c344b9f427d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index f417571..c9ca5715 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-3e5181d578e98ced73e534a9d2a1cea9867a01ac
\ No newline at end of file
+3e1c483d0192994925f8c9acfcbe9941d8b8e01b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
index 41dee06..afaca82 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-136a04daacc9abacfb19e7578724065040054592
\ No newline at end of file
+4e2766cdb2ab908217d870907c069a02bae7b528
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 8ef18860..64957bec 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-9428025753d7e88700e345f4fff9ff8387e6e8ee
\ No newline at end of file
+4375a92a996ced8c38e34f7737531f0a7992d7e8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 35568d2..c2afa078 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-bd7157be634d820901a601871f8c7d9b5bd90ef3
\ No newline at end of file
+6f3806dc086bf321df97c877cb75ae78fd77b53d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 8ff62c1..4e1786bf7 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-22f1a435b4edaff88f77677655906444538d4b19
\ No newline at end of file
+98a61905f7f4d3e3988b3bd205c75b96cacf0c0a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 9681b6a1..13faeb3 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-70ff6f2a5053e0276d3bc294434af1850960ab99
\ No newline at end of file
+c2bd50dbfaaf65e280ec3918608674d35148c22d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index df544042..6a7c205 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-d80c90c02832e963ffdaa045d495a5aeb87a7fd0
\ No newline at end of file
+dbdfbdd3574c775d8a0eea9cab7d1617cd0df848
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
index fa72440c..58ee1390 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-b1105b7a702684865dac9144b8e15ea2c3f23c9c
\ No newline at end of file
+2e1a758312ffb1a74535a1652746c7c1caf2ad27
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 8096f6b..f8d97a9 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-7d464e22063f50bcaf0374ea6b479955b7f5e603
\ No newline at end of file
+9bf769b5baf74730a6c141aeec79af8dce382e9b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 5e9637f..5f494916 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-5895813ecd4bcaca8173d53378a1751b937e377f
\ No newline at end of file
+d6b6db16b57464f52d4b0629f5a657e088679a21
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index a0584173..289cf38 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-b93ec69e39c958bf40c14e040a7ca09dca7925f2
\ No newline at end of file
+407a349b67c7b2b073ee4fc7f2e78063ac0b476a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
index 823666d..d3f4da07 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-2e41d3026f986e1801c221a72a96cfb784445156
\ No newline at end of file
+85709b6edd99a71c4f8df626f86d8038bf818854
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 7f551ca..41d3691 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-43a83d0847b49c1f052b37a1ad4a01735e89e0b0
\ No newline at end of file
+941de4e0f01f6f6d8cf2339b69fecfc42dfba478
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
index ac8f2bd..1d24c7e 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-9dd29addeda2cc80f1afafc12c25bc1bc0baba3c
\ No newline at end of file
+56b24be303660dfd1b94ffdb3bb6fc404f0e8c93
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/bwg/bwg_api.h b/ios/public/provider/chrome/browser/bwg/bwg_api.h
index af0dfd54..16fe336 100644
--- a/ios/public/provider/chrome/browser/bwg/bwg_api.h
+++ b/ios/public/provider/chrome/browser/bwg/bwg_api.h
@@ -12,6 +12,7 @@
 #import "components/optimization_guide/proto/features/common_quality_data.pb.h"
 #import "services/network/public/cpp/resource_request.h"
 
+class AuthenticationService;
 @class BWGConfiguration;
 @protocol BWGGatewayProtocol;
 
@@ -54,6 +55,11 @@
 // Creates a BWG gateway object for relaying internal protocols.
 id<BWGGatewayProtocol> CreateBWGGateway();
 
+// Checks if the feature is disabled through a Gemini Enterprise policy, and
+// returns the result through a `completion` block.
+void CheckGeminiEligibility(AuthenticationService* auth_service,
+                            BWGEligibilityCallback completion);
+
 }  // namespace ios::provider
 
 #endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BWG_BWG_API_H_
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 26e5b78..90aa60b 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -1265,7 +1265,13 @@
 }
 
 // Tests that calling document.write() on a newly-opened window doesn't crash.
-TEST_F(WindowOpenByDomTest, DocumentWrite) {
+// TODO(crbug.com/433776063): The test fails on device.
+#if TARGET_OS_SIMULATOR
+#define MAYBE_DocumentWrite DocumentWrite
+#else
+#define MAYBE_DocumentWrite DISABLED_DocumentWrite
+#endif
+TEST_F(WindowOpenByDomTest, MAYBE_DocumentWrite) {
   delegate_.allow_popups(opener_url_);
 
   NSString* const kDocumentWriteScript =
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm
index 2284ecf..88d5b0f 100644
--- a/ios/web/web_state/web_state_unittest.mm
+++ b/ios/web/web_state/web_state_unittest.mm
@@ -163,11 +163,11 @@
         int white_pixel_x = (snapshot.size.width / 2) + 10;
         // Test a pixel on the left (red) side.
         gfx::test::CheckColors(
-            gfx::test::GetPlatformImageColor(snapshot, red_pixel_x, 50),
+            gfx::test::GetPlatformImageColor(snapshot, red_pixel_x, 60),
             SK_ColorRED);
         // Test a pixel on the right (white) side.
         gfx::test::CheckColors(
-            gfx::test::GetPlatformImageColor(snapshot, white_pixel_x, 50),
+            gfx::test::GetPlatformImageColor(snapshot, white_pixel_x, 60),
             SK_ColorWHITE);
         snapshot_complete = true;
       }));
@@ -177,7 +177,13 @@
 }
 
 // Tests that the create PDF method returns a PDF of a rendered html page.
-TEST_F(WebStateTest, CreateFullPagePdf_ValidURL) {
+// TODO(crbug.com/433740395): Re-enable tests
+#if TARGET_OS_SIMULATOR
+#define MAYBE_CreateFullPagePdf_ValidURL CreateFullPagePdf_ValidURL
+#else
+#define MAYBE_CreateFullPagePdf_ValidURL DISABLED_CreateFullPagePdf_ValidURL
+#endif
+TEST_F(WebStateTest, MAYBE_CreateFullPagePdf_ValidURL) {
   [GetAnyKeyWindow() addSubview:web_state()->GetView()];
 
   // Load a URL and some HTML in the WebState.
@@ -320,7 +326,13 @@
 
 // Verifies that large session can be restored with max session size limit
 // equals to `wk_navigation_util::kMaxSessionSize`.
-TEST_F(WebStateTest, RestoreLargeSession) {
+// TODO(crbug.com/433740395): Re-enable tests
+#if TARGET_OS_SIMULATOR
+#define MAYBE_RestoreLargeSession RestoreLargeSession
+#else
+#define MAYBE_RestoreLargeSession DISABLED_RestoreLargeSession
+#endif
+TEST_F(WebStateTest, MAYBE_RestoreLargeSession) {
   // Create session storage with large number of items.
   const int kItemCount = 150;
   std::unique_ptr<WebState> web_state =
@@ -424,7 +436,13 @@
 // Verifies that calling WebState::Stop() does not stop the session restoration.
 // Session restoration should be opaque to the user and embedder, so calling
 // Stop() is no-op.
-TEST_F(WebStateTest, CallStopDuringSessionRestore) {
+// TODO(crbug.com/433740395): Re-enable tests
+#if TARGET_OS_SIMULATOR
+#define MAYBE_CallStopDuringSessionRestore CallStopDuringSessionRestore
+#else
+#define MAYBE_CallStopDuringSessionRestore DISABLED_CallStopDuringSessionRestore
+#endif
+TEST_F(WebStateTest, MAYBE_CallStopDuringSessionRestore) {
   // Create session storage with large number of items.
   const int kItemCount = 10;
   std::unique_ptr<WebState> web_state =
@@ -505,7 +523,14 @@
 // Verifies that calling NavigationManager::Reload() does not stop the session
 // restoration. Session restoration should be opaque to the user and embedder,
 // so calling Reload() is no-op.
-TEST_F(WebStateTest, CallReloadDuringSessionRestore) {
+// TODO(crbug.com/433740395): Re-enable tests
+#if TARGET_OS_SIMULATOR
+#define MAYBE_CallReloadDuringSessionRestore CallReloadDuringSessionRestore
+#else
+#define MAYBE_CallReloadDuringSessionRestore \
+  DISABLED_CallReloadDuringSessionRestore
+#endif
+TEST_F(WebStateTest, MAYBE_CallReloadDuringSessionRestore) {
   // Create session storage with large number of items.
   const int kItemCount = 10;
   std::unique_ptr<WebState> web_state =
diff --git a/ios/web_view/internal/passwords/web_view_password_feature_manager.h b/ios/web_view/internal/passwords/web_view_password_feature_manager.h
index c97d084..6992d3b 100644
--- a/ios/web_view/internal/passwords/web_view_password_feature_manager.h
+++ b/ios/web_view/internal/passwords/web_view_password_feature_manager.h
@@ -12,15 +12,13 @@
 class SyncService;
 }  // namespace syncer
 
-class PrefService;
-
 namespace ios_web_view {
 // An //ios/web_view implementation of password_manager::PasswordFeatureManager.
 class WebViewPasswordFeatureManager
     : public password_manager::PasswordFeatureManager {
  public:
-  WebViewPasswordFeatureManager(PrefService* pref_service,
-                                const syncer::SyncService* sync_service);
+  explicit WebViewPasswordFeatureManager(
+      const syncer::SyncService* sync_service);
 
   WebViewPasswordFeatureManager(const WebViewPasswordFeatureManager&) = delete;
   WebViewPasswordFeatureManager& operator=(
@@ -37,7 +35,6 @@
   bool IsBiometricAuthenticationBeforeFillingEnabled() const override;
 
  private:
-  const raw_ptr<PrefService> pref_service_;
   const raw_ptr<const syncer::SyncService> sync_service_;
 };
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/passwords/web_view_password_feature_manager.mm b/ios/web_view/internal/passwords/web_view_password_feature_manager.mm
index ea2bdd68b..d716d73d 100644
--- a/ios/web_view/internal/passwords/web_view_password_feature_manager.mm
+++ b/ios/web_view/internal/passwords/web_view_password_feature_manager.mm
@@ -6,14 +6,12 @@
 
 #import "base/notreached.h"
 #import "components/password_manager/core/browser/features/password_manager_features_util.h"
-#import "components/prefs/pref_service.h"
 #import "components/sync/service/sync_service.h"
 
 namespace ios_web_view {
 WebViewPasswordFeatureManager::WebViewPasswordFeatureManager(
-    PrefService* pref_service,
     const syncer::SyncService* sync_service)
-    : pref_service_(pref_service), sync_service_(sync_service) {}
+    : sync_service_(sync_service) {}
 
 bool WebViewPasswordFeatureManager::IsGenerationEnabled() const {
   return true;
@@ -24,7 +22,7 @@
   // still be controlled on a per user basis to ensure that the logged out user
   // remains with account storage disabled.
   return password_manager::features_util::IsAccountStorageEnabled(
-      pref_service_, sync_service_);
+      sync_service_);
 }
 
 password_manager::features_util::PasswordAccountStorageUsageLevel
diff --git a/ios/web_view/internal/passwords/web_view_password_manager_client.mm b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
index 5906ef22..c5b21e5 100644
--- a/ios/web_view/internal/passwords/web_view_password_manager_client.mm
+++ b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
@@ -83,7 +83,7 @@
       profile_store_(profile_store),
       account_store_(account_store),
       reuse_manager_(reuse_manager),
-      password_feature_manager_(pref_service, sync_service),
+      password_feature_manager_(sync_service),
       credentials_filter_(this),
       requirements_service_(requirements_service),
       helper_(this) {
diff --git a/ios/web_view/internal/sync/cwv_sync_controller.mm b/ios/web_view/internal/sync/cwv_sync_controller.mm
index 8c9b66d..675a450 100644
--- a/ios/web_view/internal/sync/cwv_sync_controller.mm
+++ b/ios/web_view/internal/sync/cwv_sync_controller.mm
@@ -155,8 +155,8 @@
   autofill::SetUserOptedInWalletSyncTransport(_prefService, accountId,
                                               /*opted_in=*/true);
   if (!CWVWebView.skipAccountStorageCheckEnabled) {
-    CHECK(password_manager::features_util::IsAccountStorageEnabled(
-        _prefService, _syncService));
+    CHECK(
+        password_manager::features_util::IsAccountStorageEnabled(_syncService));
   }
 }
 
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
index ff7d0d98..1175b28 100644
--- a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
+++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -88,8 +88,8 @@
   // Ensure opt-ins for transport only sync data is flipped to true.
   EXPECT_TRUE(autofill::IsUserOptedInWalletSyncTransport(
       &pref_service_, primary_account_info.account_id));
-  EXPECT_TRUE(password_manager::features_util::IsAccountStorageEnabled(
-      &pref_service_, &sync_service_));
+  EXPECT_TRUE(
+      password_manager::features_util::IsAccountStorageEnabled(&sync_service_));
 }
 
 TEST_F(CWVSyncControllerTest, StartSyncWithIdentityInAuthError) {
@@ -98,8 +98,8 @@
       identity_test_environment_.MakeAccountAvailable(kTestEmail);
   sync_service_.SetSignedIn(signin::ConsentLevel::kSignin, account_info);
   sync_service_.SetPersistentAuthError();
-  ASSERT_FALSE(password_manager::features_util::IsAccountStorageEnabled(
-      &pref_service_, &sync_service_));
+  ASSERT_FALSE(
+      password_manager::features_util::IsAccountStorageEnabled(&sync_service_));
 
   // Should not crash.
   CWVSyncController* sync_controller = [[CWVSyncController alloc]
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h
index 61ee4e6..d9614f3 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.h
+++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -40,9 +40,6 @@
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
   syncer::SyncEngineFactory* GetSyncEngineFactory() override;
   bool IsCustomPassphraseAllowed() override;
-  bool IsPasswordSyncAllowed() override;
-  void SetPasswordSyncAllowedChangeCb(
-      const base::RepeatingClosure& cb) override;
   void RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial(
       const syncer::TrustedVaultAutoUpgradeSyntheticFieldTrialGroup& group)
       override;
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 399afb82..1e63f85 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -79,15 +79,6 @@
   return true;
 }
 
-bool WebViewSyncClient::IsPasswordSyncAllowed() {
-  return true;
-}
-
-void WebViewSyncClient::SetPasswordSyncAllowedChangeCb(
-    const base::RepeatingClosure& cb) {
-  // IsPasswordSyncAllowed() doesn't change on //ios/web_view/.
-}
-
 void WebViewSyncClient::RegisterTrustedVaultAutoUpgradeSyntheticFieldTrial(
     const syncer::TrustedVaultAutoUpgradeSyntheticFieldTrialGroup& group) {
   // This code might be reached but synthetic field trials are not supported on
diff --git a/ios_internal b/ios_internal
index 18fdedf..a395fb5 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 18fdedfc327e6ab87a6c1d733169edad7b30565c
+Subproject commit a395fb5e17820c37cf1ce6ac9f35b13624638818
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index 6b763e6..6b566e0 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -226,20 +226,6 @@
   ]
 }
 
-static_library("test_sink") {
-  testonly = true
-  sources = [
-    "ipc_security_test_util.cc",
-    "ipc_security_test_util.h",
-  ]
-  public_deps = [ ":ipc" ]
-  deps = [
-    "//base",
-    "//base/test:test_support",
-    "//mojo/core/test:test_support",
-  ]
-}
-
 if (use_blink) {
   source_set("run_all_unittests") {
     testonly = true
@@ -343,10 +329,7 @@
       "ipc_test_channel_listener.cc",
       "ipc_test_channel_listener.h",
     ]
-    public_deps = [
-      ":ipc",
-      ":test_sink",
-    ]
+    public_deps = [ ":ipc" ]
     deps = [
       "//base",
       "//base/test:test_support",
diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h
index 6a74f90..dc1852d 100644
--- a/ipc/ipc_channel_proxy.h
+++ b/ipc/ipc_channel_proxy.h
@@ -308,7 +308,6 @@
 
    private:
     friend class ChannelProxy;
-    friend class IpcSecurityTestUtil;
 
     // Create the Channel
     void CreateChannel(std::unique_ptr<ChannelFactory> factory);
@@ -399,8 +398,6 @@
   void SendInternal(Message* message);
 
  private:
-  friend class IpcSecurityTestUtil;
-
   template <typename Interface>
   static void BindPendingAssociatedReceiver(
       const AssociatedInterfaceFactory<Interface>& factory,
diff --git a/ipc/ipc_security_test_util.cc b/ipc/ipc_security_test_util.cc
deleted file mode 100644
index 35ff187e..0000000
--- a/ipc/ipc_security_test_util.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ipc/ipc_security_test_util.h"
-
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/run_loop.h"
-#include "ipc/ipc_channel_proxy.h"
-
-namespace IPC {
-
-void IpcSecurityTestUtil::PwnMessageReceived(ChannelProxy* channel,
-                                             const IPC::Message& message) {
-  base::RunLoop run_loop;
-  base::OnceClosure inject_message = base::BindOnce(
-      base::IgnoreResult(&IPC::ChannelProxy::Context::OnMessageReceived),
-      channel->context(), message);
-  channel->context()->ipc_task_runner()->PostTaskAndReply(
-      FROM_HERE, std::move(inject_message), run_loop.QuitClosure());
-  run_loop.Run();
-}
-
-}  // namespace IPC
diff --git a/ipc/ipc_security_test_util.h b/ipc/ipc_security_test_util.h
deleted file mode 100644
index 6579503..0000000
--- a/ipc/ipc_security_test_util.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPC_IPC_SECURITY_TEST_UTIL_H_
-#define IPC_IPC_SECURITY_TEST_UTIL_H_
-
-namespace IPC {
-
-class ChannelProxy;
-class Message;
-
-class IpcSecurityTestUtil {
- public:
-  IpcSecurityTestUtil(const IpcSecurityTestUtil&) = delete;
-  IpcSecurityTestUtil& operator=(const IpcSecurityTestUtil&) = delete;
-
-  // Enables testing of security exploit scenarios where a compromised child
-  // process can send a malicious message of an arbitrary type.
-  //
-  // This function will post the message to the IPC channel's thread, where it
-  // is offered to the channel's listeners. Afterwards, a reply task is posted
-  // back to the current thread. This function blocks until the reply task is
-  // received. For messages forwarded back to the current thread, we won't
-  // return until after the message has been handled here.
-  //
-  // Use this only for testing security bugs in a browsertest; other uses are
-  // likely perilous. Unit tests should be using IPC::TestSink which has an
-  // OnMessageReceived method you can call directly. Non-security browsertests
-  // should just exercise the child process's normal codepaths to send messages.
-  static void PwnMessageReceived(ChannelProxy* channel, const Message& message);
-
- private:
-  IpcSecurityTestUtil();  // Not instantiable.
-};
-
-}  // namespace IPC
-
-#endif  // IPC_IPC_SECURITY_TEST_UTIL_H_
diff --git a/media/BUILD.gn b/media/BUILD.gn
index eb63010a..05fd55e 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -269,6 +269,8 @@
 
   if (is_ios) {
     deps += [ ":unit_tests_bundle_data" ]
+    bundle_deps =
+        [ "//testing/buildbot/filters:media_unittests_filters_bundle_data" ]
   }
 }
 
diff --git a/media/base/media_player_logging_id.h b/media/base/media_player_logging_id.h
index 380188a..71f30cf 100644
--- a/media/base/media_player_logging_id.h
+++ b/media/base/media_player_logging_id.h
@@ -13,7 +13,7 @@
 namespace media {
 
 // alias the name for readability
-using MediaPlayerLoggingID = int32_t;
+using MediaPlayerLoggingID = int64_t;
 
 MEDIA_EXPORT MediaPlayerLoggingID GetNextMediaPlayerLoggingID();
 
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index ebf6e43..b29722d 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -1787,6 +1787,11 @@
              "HeadlessLiveCaption",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Allows per-site special processing for media links.
+BASE_FEATURE(kMediaLinkHelpers,
+             "MediaLinkHelpers",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 bool IsChromeWideEchoCancellationEnabled() {
 #if BUILDFLAG(CHROME_WIDE_ECHO_CANCELLATION)
   return base::FeatureList::IsEnabled(kChromeWideEchoCancellation) &&
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 5dca8e4..02ed57e2 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -543,6 +543,9 @@
 // Enable experimental headless captions.
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kHeadlessLiveCaption);
 
+// Enable site-specific media link helpers.
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kMediaLinkHelpers);
+
 // Based on a |command_line| and the current platform, returns the effective
 // autoplay policy. In other words, it will take into account the default policy
 // if none is specified via the command line and options passed for testing.
diff --git a/media/base/silent_sink_suspender.cc b/media/base/silent_sink_suspender.cc
index bfb76d89..c1595c7 100644
--- a/media/base/silent_sink_suspender.cc
+++ b/media/base/silent_sink_suspender.cc
@@ -6,6 +6,7 @@
 
 #include "base/functional/bind.h"
 #include "base/task/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
 #include "media/base/audio_glitch_info.h"
 
 namespace media {
@@ -187,6 +188,10 @@
       is_transition_pending_ = false;
       is_using_fake_sink_ = true;
     }
+
+    TRACE_EVENT_INSTANT0(
+        "audio", "SilentSinkSuspender::TransitionSinks - fake_sink_.Start()",
+        TRACE_EVENT_SCOPE_THREAD);
     fake_sink_.Start(base::BindRepeating(
         [](SilentSinkSuspender* suspender, base::TimeDelta frozen_delay,
            base::TimeTicks frozen_delay_timestamp, base::TimeTicks ideal_time,
@@ -199,6 +204,9 @@
         },
         this, latest_output_delay_, latest_output_delay_timestamp_));
   } else {
+    TRACE_EVENT_INSTANT0(
+        "audio", "SilentSinkSuspender::TransitionSinks - fake_sink_.Stop()",
+        TRACE_EVENT_SCOPE_THREAD);
     fake_sink_.Stop();
 
     // Despite the fake sink having a synchronous Stop(), if this transition
diff --git a/media/capture/video/linux/v4l2_gpu_memory_buffer_tracker.cc b/media/capture/video/linux/v4l2_gpu_memory_buffer_tracker.cc
index 730ff9b..09f107f7 100644
--- a/media/capture/video/linux/v4l2_gpu_memory_buffer_tracker.cc
+++ b/media/capture/video/linux/v4l2_gpu_memory_buffer_tracker.cc
@@ -6,7 +6,7 @@
 
 #include <optional>
 
-#include "components/viz/common/resources/shared_image_format_utils.h"
+#include "components/viz/common/resources/shared_image_format.h"
 #include "gpu/command_buffer/client/client_shared_image.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "media/capture/video/video_capture_buffer_handle.h"
@@ -16,24 +16,23 @@
 namespace media {
 
 namespace {
-// Converts the video pixel format |pixel_format| to gfx::BufferFormat.
-std::optional<gfx::BufferFormat> ToBufferFormat(VideoPixelFormat pixel_format) {
+// Converts the video pixel format |pixel_format| to viz::SharedImageFormat.
+std::optional<viz::SharedImageFormat> ToSharedImageFormat(
+    VideoPixelFormat pixel_format) {
   switch (pixel_format) {
     case PIXEL_FORMAT_NV12:
-      return gfx::BufferFormat::YUV_420_BIPLANAR;
+      return viz::MultiPlaneFormat::kNV12;
     default:
       return std::nullopt;
   }
 }
 
-gfx::BufferUsage GetBufferUsage(gfx::BufferFormat format) {
-  switch (format) {
-    case gfx::BufferFormat::YUV_420_BIPLANAR:
-      return gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
-    default:
-      // Default usage for YUV camera buffer.
-      return gfx::BufferUsage::SCANOUT_CPU_READ_WRITE;
+gfx::BufferUsage GetBufferUsage(viz::SharedImageFormat format) {
+  if (format == viz::MultiPlaneFormat::kNV12) {
+    return gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
   }
+  // Default usage for YUV camera buffer.
+  return gfx::BufferUsage::SCANOUT_CPU_READ_WRITE;
 }
 }  // namespace
 
@@ -45,13 +44,13 @@
 bool V4L2GpuMemoryBufferTracker::Init(const gfx::Size& dimensions,
                                       VideoPixelFormat format,
                                       const mojom::PlaneStridesPtr& strides) {
-  std::optional<gfx::BufferFormat> gfx_format = ToBufferFormat(format);
-  if (!gfx_format) {
+  std::optional<viz::SharedImageFormat> si_format = ToSharedImageFormat(format);
+  if (!si_format) {
     DLOG(ERROR) << "Unsupported VideoPixelFormat "
                 << VideoPixelFormatToString(format);
     return false;
   }
-  gfx::BufferUsage usage = GetBufferUsage(*gfx_format);
+  gfx::BufferUsage usage = GetBufferUsage(*si_format);
 
   auto sii =
       VideoCaptureGpuChannelHost::GetInstance().GetSharedImageInterface();
@@ -63,9 +62,8 @@
   // Setting some default usage in order to get a mappable shared image.
   const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY |
                         gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
-  const auto si_format = viz::GetSharedImageFormat(*gfx_format);
   shared_image_ = sii->CreateSharedImage(
-      {si_format, dimensions, gfx::ColorSpace(),
+      {*si_format, dimensions, gfx::ColorSpace(),
        gpu::SharedImageUsageSet(si_usage), "V4L2GpuMemoryBufferTracker"},
       gpu::kNullSurfaceHandle, usage);
   if (!shared_image_) {
@@ -86,11 +84,11 @@
     return false;
   }
 
-  std::optional<gfx::BufferFormat> gfx_format = ToBufferFormat(format);
-  if (!gfx_format) {
+  std::optional<viz::SharedImageFormat> si_format = ToSharedImageFormat(format);
+  if (!si_format) {
     return false;
   }
-  return (viz::GetSharedImageFormat(*gfx_format) == shared_image_->format() &&
+  return (*si_format == shared_image_->format() &&
           dimensions == shared_image_->size());
 }
 
diff --git a/media/capture/video/win/video_capture_device_mf_win.cc b/media/capture/video/win/video_capture_device_mf_win.cc
index fbdf8cc..1eb7884f 100644
--- a/media/capture/video/win/video_capture_device_mf_win.cc
+++ b/media/capture/video/win/video_capture_device_mf_win.cc
@@ -527,14 +527,16 @@
   // nominal range attribute from source to sink instead of rewriting it to
   // limited range. See https://crbug.com/1449570 for more details.
   if (base::FeatureList::IsEnabled(media::kWebRTCColorAccuracy)) {
-    hr = CopyAttribute(source_media_type, sink_media_type,
-                       MF_MT_VIDEO_NOMINAL_RANGE);
+    // Not checking return value, since the attribute may be missing.
+    CopyAttribute(source_media_type, sink_media_type,
+                  MF_MT_VIDEO_NOMINAL_RANGE);
   } else {
     hr = sink_media_type->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE,
                                     MFNominalRange_16_235);
+    if (FAILED(hr)) {
+      return hr;
+    }
   }
-  if (FAILED(hr))
-    return hr;
 
   // Next three attributes may be missing, unless a HDR video is captured so
   // ignore errors.
diff --git a/media/gpu/v4l2/test/vp9_decoder.cc b/media/gpu/v4l2/test/vp9_decoder.cc
index 67a84e0..ef29147 100644
--- a/media/gpu/v4l2/test/vp9_decoder.cc
+++ b/media/gpu/v4l2/test/vp9_decoder.cc
@@ -13,6 +13,8 @@
 #include <linux/videodev2.h>
 #include <sys/ioctl.h>
 
+#include <bitset>
+
 #include "base/bits.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/logging.h"
diff --git a/media/mojo/services/media_metrics_provider.h b/media/mojo/services/media_metrics_provider.h
index 705300b..e4c72bb 100644
--- a/media/mojo/services/media_metrics_provider.h
+++ b/media/mojo/services/media_metrics_provider.h
@@ -13,6 +13,7 @@
 #include "base/time/time.h"
 #include "media/base/container_names.h"
 #include "media/base/demuxer.h"
+#include "media/base/media_player_logging_id.h"
 #include "media/base/picture_in_picture_events_info.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/renderer_factory_selector.h"
@@ -152,7 +153,7 @@
 
   // Session unique ID which maps to a given WebMediaPlayerImpl instances. Used
   // to coordinate multiply logged events with a singly logged metric.
-  const uint64_t player_id_;
+  const MediaPlayerLoggingID player_id_;
 
   // Are UKM reports for the main frame or for a subframe?
   const bool is_top_frame_;
diff --git a/media/mojo/services/video_decode_stats_recorder.cc b/media/mojo/services/video_decode_stats_recorder.cc
index 966a83f..e244f21 100644
--- a/media/mojo/services/video_decode_stats_recorder.cc
+++ b/media/mojo/services/video_decode_stats_recorder.cc
@@ -16,7 +16,7 @@
     ukm::SourceId source_id,
     learning::FeatureValue origin,
     bool is_top_frame,
-    uint64_t player_id)
+    MediaPlayerLoggingID player_id)
     : save_cb_(std::move(save_cb)),
       source_id_(source_id),
       origin_(origin),
diff --git a/media/mojo/services/video_decode_stats_recorder.h b/media/mojo/services/video_decode_stats_recorder.h
index c4302fe..5a0546c 100644
--- a/media/mojo/services/video_decode_stats_recorder.h
+++ b/media/mojo/services/video_decode_stats_recorder.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "media/base/media_player_logging_id.h"
 #include "media/base/video_codecs.h"
 #include "media/learning/common/value.h"
 #include "media/mojo/mojom/media_types.mojom.h"
@@ -27,7 +28,7 @@
                            ukm::SourceId source_id,
                            learning::FeatureValue origin,
                            bool is_top_frame,
-                           uint64_t player_id);
+                           MediaPlayerLoggingID player_id);
 
   VideoDecodeStatsRecorder(const VideoDecodeStatsRecorder&) = delete;
   VideoDecodeStatsRecorder& operator=(const VideoDecodeStatsRecorder&) = delete;
@@ -47,7 +48,7 @@
   const ukm::SourceId source_id_;
   const learning::FeatureValue origin_;
   const bool is_top_frame_;
-  const uint64_t player_id_;
+  const MediaPlayerLoggingID player_id_;
 
   mojom::PredictionFeatures features_;
   mojom::PredictionTargets targets_;
diff --git a/media/mojo/services/watch_time_recorder.cc b/media/mojo/services/watch_time_recorder.cc
index e50e6999..d6eb2e9 100644
--- a/media/mojo/services/watch_time_recorder.cc
+++ b/media/mojo/services/watch_time_recorder.cc
@@ -68,7 +68,7 @@
     mojom::PlaybackPropertiesPtr properties,
     ukm::SourceId source_id,
     bool is_top_frame,
-    uint64_t player_id)
+    MediaPlayerLoggingID player_id)
     : auto_pip_reason_cb_(std::move(auto_pip_reason_cb)),
       properties_(std::move(properties)),
       source_id_(source_id),
diff --git a/media/mojo/services/watch_time_recorder.h b/media/mojo/services/watch_time_recorder.h
index 85195fde..71cc98b 100644
--- a/media/mojo/services/watch_time_recorder.h
+++ b/media/mojo/services/watch_time_recorder.h
@@ -13,6 +13,7 @@
 #include "base/containers/flat_map.h"
 #include "base/time/time.h"
 #include "media/base/audio_codecs.h"
+#include "media/base/media_player_logging_id.h"
 #include "media/base/picture_in_picture_events_info.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/video_codecs.h"
@@ -30,7 +31,7 @@
       mojom::PlaybackPropertiesPtr properties,
       ukm::SourceId source_id,
       bool is_top_frame,
-      uint64_t player_id);
+      MediaPlayerLoggingID player_id);
 
   WatchTimeRecorder(const WatchTimeRecorder&) = delete;
   WatchTimeRecorder& operator=(const WatchTimeRecorder&) = delete;
@@ -88,7 +89,7 @@
   // The provider ID which constructed this recorder. Used to record a UKM entry
   // at destruction that can be correlated with the final status for the
   // associated WebMediaPlayerImpl instance.
-  const uint64_t player_id_;
+  const MediaPlayerLoggingID player_id_;
 
   // Mapping of WatchTime metric keys to MeanTimeBetweenRebuffers (MTBR), smooth
   // rate (had zero rebuffers), and discard (<7s watch time) keys.
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
index 3d887c71..1b2a4a94 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -115,11 +115,11 @@
 
     int dimension_aligned = (dimension + 1) & ~1;
     y_data_ =
-        base::HeapArray<uint8_t>::Uninit(multiplier * dimension * dimension);
-    u_data_ = base::HeapArray<uint8_t>::Uninit(multiplier * dimension_aligned *
-                                               dimension_aligned / 4);
-    v_data_ = base::HeapArray<uint8_t>::Uninit(multiplier * dimension_aligned *
-                                               dimension_aligned / 4);
+        base::HeapArray<uint8_t>::WithSize(multiplier * dimension * dimension);
+    u_data_ = base::HeapArray<uint8_t>::WithSize(
+        multiplier * dimension_aligned * dimension_aligned / 4);
+    v_data_ = base::HeapArray<uint8_t>::WithSize(
+        multiplier * dimension_aligned * dimension_aligned / 4);
 
     // Initialize the last pixel of each plane
     int y_size = multiplier * dimension * dimension;
@@ -393,10 +393,6 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOne10BppHardwareFrameWithOddSize) {
-#if BUILDFLAG(IS_MAC)
-  // TODO(crbug.com/366375486): Resolve data mismatch failure and re-enable.
-  GTEST_SKIP();
-#else
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(17, 10);
   scoped_refptr<VideoFrame> frame;
@@ -423,10 +419,30 @@
     ASSERT_EQ(kYValue, y_plane_data[288]);
     ASSERT_EQ(kUValue, u_plane_data[80]);
     ASSERT_EQ(kVValue, v_plane_data[80]);
+
+    // Compare the last pixel of each plane in |software_frame| and |frame|.
+    auto* client_si = sii_->MostRecentMappableSharedImage();
+    EXPECT_TRUE(!!client_si);
+    auto mapping = client_si->Map();
+
+    // Note: The output is in YV12, i.e. the `u` and `v` planes are swapped.
+    const auto* y_memory =
+        reinterpret_cast<uint8_t*>(mapping->GetMemoryForPlane(0).data());
+    const auto* v_memory =
+        reinterpret_cast<uint8_t*>(mapping->GetMemoryForPlane(1).data());
+    const auto* u_memory =
+        reinterpret_cast<uint8_t*>(mapping->GetMemoryForPlane(2).data());
+
+    auto y_stride = mapping->Stride(0);
+    EXPECT_EQ(y_plane_data[288] >> 2, y_memory[y_stride * 16 + 16]);
+    auto v_stride = mapping->Stride(1);
+    EXPECT_EQ(v_plane_data[80] >> 2, v_memory[v_stride * 8 + 8]);
+    auto u_stride = mapping->Stride(2);
+    EXPECT_EQ(u_plane_data[80] >> 2, u_memory[u_stride * 8 + 8]);
+
   } else {
     EXPECT_EQ(software_frame.get(), frame.get());
   }
-#endif
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, ReuseFirstResource) {
@@ -598,6 +614,26 @@
               software_frame->visible_data(VideoFrame::Plane::kUV)[9246]);
     ASSERT_EQ(kVValue,
               software_frame->visible_data(VideoFrame::Plane::kUV)[9247]);
+
+    auto* client_si = sii_->MostRecentMappableSharedImage();
+    EXPECT_TRUE(!!client_si);
+    auto mapping = client_si->Map();
+
+    const auto* y_memory =
+        reinterpret_cast<uint8_t*>(mapping->GetMemoryForPlane(0).data());
+    const auto* uv_memory =
+        reinterpret_cast<uint8_t*>(mapping->GetMemoryForPlane(1).data());
+
+    // Compare the last pixel of each plane in |software_frame| and |frame|.
+    // y_memory = 135x135, uv_memory = 136x68.
+    auto y_stride = mapping->Stride(0);
+    EXPECT_EQ(software_frame->visible_data(VideoFrame::Plane::kY)[18224],
+              y_memory[y_stride * 134 + 134]);
+    auto uv_stride = mapping->Stride(1);
+    EXPECT_EQ(software_frame->visible_data(VideoFrame::Plane::kUV)[9246],
+              uv_memory[uv_stride * 67 + 134]);
+    EXPECT_EQ(software_frame->visible_data(VideoFrame::Plane::kUV)[9247],
+              uv_memory[uv_stride * 67 + 135]);
   } else {
     EXPECT_EQ(software_frame.get(), frame.get());
   }
@@ -639,10 +675,6 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOneHardwareP010FrameWithOddSize) {
-#if BUILDFLAG(IS_MAC)
-  // TODO(crbug.com/366375486): Resolve data mismatch failure and re-enable.
-  GTEST_SKIP();
-#else
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(7, 10);
   scoped_refptr<VideoFrame> frame;
@@ -675,7 +707,6 @@
   } else {
     EXPECT_EQ(software_frame.get(), frame.get());
   }
-#endif
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareXR30FrameBT709) {
diff --git a/media/video/video_encode_accelerator_adapter.cc b/media/video/video_encode_accelerator_adapter.cc
index 9120903..01bea74 100644
--- a/media/video/video_encode_accelerator_adapter.cc
+++ b/media/video/video_encode_accelerator_adapter.cc
@@ -19,7 +19,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "components/viz/common/resources/shared_image_format_utils.h"
+#include "components/viz/common/resources/shared_image_format.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/base/encoder_status.h"
 #include "media/base/media_log.h"
@@ -173,8 +173,7 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     DCHECK(gfx::Rect(coded_size_).Contains(gfx::Rect(visible_size)));
 
-    const auto buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
-    const auto si_format = viz::GetSharedImageFormat(buffer_format);
+    const auto si_format = viz::MultiPlaneFormat::kNV12;
     const auto buffer_usage =
         gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE;
 
diff --git a/mojo/core/data_pipe_unittest.cc b/mojo/core/data_pipe_unittest.cc
index c0b3234..86924b34 100644
--- a/mojo/core/data_pipe_unittest.cc
+++ b/mojo/core/data_pipe_unittest.cc
@@ -2104,8 +2104,9 @@
 
   MojoHandle handles[6];
   EXPECT_EQ("o_O", ReadMessageWithHandles(parent, handles, 6));
-  MojoHandle* producers = &handles[0];
-  MojoHandle* consumers = &handles[3];
+  base::span<MojoHandle> producers = handles;
+  base::span<MojoHandle> consumers =
+      base::span<MojoHandle>(handles).subspan(3u);
 
   // Wait on producer 0
   EXPECT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/core/message_unittest.cc b/mojo/core/message_unittest.cc
index 20822a4..c641df13 100644
--- a/mojo/core/message_unittest.cc
+++ b/mojo/core/message_unittest.cc
@@ -8,11 +8,13 @@
 #endif
 
 #include <algorithm>
+#include <array>
 #include <memory>
 #include <string_view>
 #include <utility>
 #include <vector>
 
+#include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
@@ -81,7 +83,7 @@
 
  protected:
   virtual void GetSerializedSize(size_t* num_bytes, size_t* num_handles) = 0;
-  virtual void SerializeHandles(MojoHandle* handles) = 0;
+  virtual void SerializeHandles(base::span<MojoHandle> handles) = 0;
   virtual void SerializePayload(void* buffer) = 0;
 
  private:
@@ -93,7 +95,7 @@
     message->GetSerializedSize(&num_bytes, &num_handles);
     std::vector<MojoHandle> handles(num_handles);
     if (num_handles)
-      message->SerializeHandles(handles.data());
+      message->SerializeHandles(handles);
 
     MojoAppendMessageDataOptions options;
     options.struct_size = sizeof(options);
@@ -134,7 +136,9 @@
   void GetSerializedSize(size_t* num_bytes, size_t* num_handles) override {
     NOTREACHED();
   }
-  void SerializeHandles(MojoHandle* handles) override { NOTREACHED(); }
+  void SerializeHandles(base::span<MojoHandle> handles) override {
+    NOTREACHED();
+  }
   void SerializePayload(void* buffer) override { NOTREACHED(); }
 
   base::OnceClosure destruction_callback_;
@@ -168,7 +172,7 @@
     *num_handles = handles_.size();
   }
 
-  void SerializeHandles(MojoHandle* handles) override {
+  void SerializeHandles(base::span<MojoHandle> handles) override {
     ASSERT_TRUE(!handles_.empty());
     for (size_t i = 0; i < handles_.size(); ++i)
       handles[i] = handles_[i].release().value();
@@ -1092,7 +1096,7 @@
   ExtendPayloadWithHandlesAttachedViaExtension
 #endif  // BUILDFLAG(IS_IOS)
 TEST_F(MessageTest, MAYBE_ExtendPayloadWithHandlesAttachedViaExtension) {
-  MojoHandle handles[5];
+  std::array<MojoHandle, 5> handles;
   CreateMessagePipe(&handles[0], &handles[4]);
   PlatformChannel channel;
   handles[1] =
@@ -1110,21 +1114,25 @@
   uint32_t buffer_size = 0;
   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
   EXPECT_EQ(MOJO_RESULT_OK,
-            MojoAppendMessageData(message, 0, handles, 1, nullptr, &buffer,
-                                  &buffer_size));
+            MojoAppendMessageData(message, 0, handles.data(), 1, nullptr,
+                                  &buffer, &buffer_size));
   uint32_t payload_size = buffer_size * 64;
   EXPECT_EQ(MOJO_RESULT_OK,
             MojoAppendMessageData(message, payload_size, nullptr, 0, nullptr,
                                   &buffer, nullptr));
 
   // Add more handles.
-  EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, handles + 1, 1,
-                                                  nullptr, &buffer, nullptr));
+  EXPECT_EQ(
+      MOJO_RESULT_OK,
+      MojoAppendMessageData(message, 0, base::span(handles).subspan(1u).data(),
+                            1, nullptr, &buffer, nullptr));
   MojoAppendMessageDataOptions options;
   options.struct_size = sizeof(options);
   options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
-  EXPECT_EQ(MOJO_RESULT_OK, MojoAppendMessageData(message, 0, handles + 2, 3,
-                                                  &options, &buffer, nullptr));
+  EXPECT_EQ(
+      MOJO_RESULT_OK,
+      MojoAppendMessageData(message, 0, base::span(handles).subspan(2u).data(),
+                            3, &options, &buffer, nullptr));
   memset(buffer, 'x', payload_size);
 
   RunTestClient("ReadMessageAndCheckPipe", [&](MojoHandle h) {
diff --git a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
index f4d4af1..58f1932 100644
--- a/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
+++ b/mojo/public/cpp/bindings/lib/wtf_clone_equals_util.h
@@ -43,7 +43,7 @@
   static bool Equals(const blink::Vector<T>& a, const blink::Vector<T>& b) {
     if (a.size() != b.size())
       return false;
-    for (wtf_size_t i = 0; i < a.size(); ++i) {
+    for (blink::wtf_size_t i = 0; i < a.size(); ++i) {
       if (!mojo::Equals(a[i], b[i]))
         return false;
     }
diff --git a/mojo/public/java/system/core_impl.cc b/mojo/public/java/system/core_impl.cc
index f2c8781..c0680e1 100644
--- a/mojo/public/java/system/core_impl.cc
+++ b/mojo/public/java/system/core_impl.cc
@@ -222,7 +222,7 @@
   MojoResult result =
       MojoBeginReadData(mojo_handle, &options, &buffer, &buffer_size);
   if (result == MOJO_RESULT_OK) {
-    ScopedJavaLocalRef<jobject> byte_buffer(
+    auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
         env, env->NewDirectByteBuffer(const_cast<void*>(buffer), buffer_size));
     base::android::CheckException(env);
     return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer);
@@ -270,7 +270,7 @@
   MojoResult result =
       MojoBeginWriteData(mojo_handle, &options, &buffer, &buffer_size);
   if (result == MOJO_RESULT_OK) {
-    ScopedJavaLocalRef<jobject> byte_buffer(
+    auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
         env, env->NewDirectByteBuffer(buffer, buffer_size));
     base::android::CheckException(env);
     return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer);
@@ -318,7 +318,7 @@
   MojoResult result =
       MojoMapBuffer(mojo_handle, offset, num_bytes, &options, &buffer);
   if (result == MOJO_RESULT_OK) {
-    ScopedJavaLocalRef<jobject> byte_buffer(
+    auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
         env, env->NewDirectByteBuffer(buffer, num_bytes));
     base::android::CheckException(env);
     return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer);
diff --git a/mojo/public/java/system/javatests/validation_test_util.cc b/mojo/public/java/system/javatests/validation_test_util.cc
index 25cd040..2a6ae640 100644
--- a/mojo/public/java/system/javatests/validation_test_util.cc
+++ b/mojo/public/java/system/javatests/validation_test_util.cc
@@ -39,7 +39,7 @@
     DCHECK(!data.size());
     data_ptr = &data;
   }
-  ScopedJavaLocalRef<jobject> byte_buffer(
+  auto byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env, env->NewDirectByteBuffer(data_ptr, data.size()));
   base::android::CheckException(env);
   return Java_ValidationTestUtil_buildData(env, byte_buffer, num_handles,
diff --git a/net/base/features.cc b/net/base/features.cc
index a8ad691..af91e79 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -670,6 +670,9 @@
 BASE_FEATURE(kDeviceBoundSessionsRefreshQuota,
              "DeviceBoundSessionsRefreshQuota",
              base::FEATURE_ENABLED_BY_DEFAULT);
+BASE_FEATURE(kDeviceBoundSessionsOriginTrialFeedback,
+             "DeviceBoundSessionsOriginTrialFeedback",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kPartitionProxyChains,
              "PartitionProxyChains",
diff --git a/net/base/features.h b/net/base/features.h
index a2a4f4b..72a8cf04 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -688,6 +688,12 @@
 // This behavior is expected by default; disabling it should only be for
 // testing purposes.
 NET_EXPORT BASE_DECLARE_FEATURE(kDeviceBoundSessionsRefreshQuota);
+// This feature will enable breaking changes to Device Bound Session
+// Credentials from after the Origin Trial started. This is disabled by
+// default to facilitate implementation of feedback from the Origin
+// Trial while still being able to get consistent metrics across Chrome
+// releases.
+NET_EXPORT BASE_DECLARE_FEATURE(kDeviceBoundSessionsOriginTrialFeedback);
 
 // When enabled, all proxies in a proxy chain are partitioned by the NAK for the
 // endpoint of the connection. When disabled, proxies carrying tunnels to other
diff --git a/net/base/net_string_util_icu_alternatives_android.cc b/net/base/net_string_util_icu_alternatives_android.cc
index cf8c047f..f7c99d68 100644
--- a/net/base/net_string_util_icu_alternatives_android.cc
+++ b/net/base/net_string_util_icu_alternatives_android.cc
@@ -23,7 +23,7 @@
 ScopedJavaLocalRef<jstring> ConvertToJstring(std::string_view text,
                                              const char* charset) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> java_byte_buffer(
+  auto java_byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env,
       env->NewDirectByteBuffer(const_cast<char*>(text.data()), text.length()));
   base::android::CheckException(env);
@@ -41,7 +41,7 @@
 ScopedJavaLocalRef<jstring> ConvertToNormalizedJstring(std::string_view text,
                                                        const char* charset) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> java_byte_buffer(
+  auto java_byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env,
       env->NewDirectByteBuffer(const_cast<char*>(text.data()), text.length()));
   base::android::CheckException(env);
@@ -59,7 +59,7 @@
     std::string_view text,
     const char* charset) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> java_byte_buffer(
+  auto java_byte_buffer = ScopedJavaLocalRef<jobject>::Adopt(
       env,
       env->NewDirectByteBuffer(const_cast<char*>(text.data()), text.length()));
   base::android::CheckException(env);
@@ -126,7 +126,7 @@
 bool ToUpperUsingLocale(std::u16string_view str, std::u16string* output) {
   output->clear();
   JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jstring> java_new_str(
+  auto java_new_str = ScopedJavaLocalRef<jstring>::Adopt(
       env,
       env->NewString(reinterpret_cast<const jchar*>(str.data()), str.length()));
   if (java_new_str.is_null())
diff --git a/net/cert/internal/trust_store_chrome.cc b/net/cert/internal/trust_store_chrome.cc
index 0d4c711..a6288be 100644
--- a/net/cert/internal/trust_store_chrome.cc
+++ b/net/cert/internal/trust_store_chrome.cc
@@ -74,29 +74,16 @@
     : ChromeRootStoreData::Anchor::Anchor(
           certificate,
           constraints,
-          /*eutl=*/false,
           /*enforce_anchor_expiry=*/false,
           /*enforce_anchor_constraints=*/false) {}
 
 ChromeRootStoreData::Anchor::Anchor(
     std::shared_ptr<const bssl::ParsedCertificate> certificate,
     std::vector<ChromeRootCertConstraints> constraints,
-    bool eutl)
-    : ChromeRootStoreData::Anchor::Anchor(
-          certificate,
-          constraints,
-          eutl,
-          /*enforce_anchor_expiry=*/false,
-          /*enforce_anchor_constraints=*/false) {}
-ChromeRootStoreData::Anchor::Anchor(
-    std::shared_ptr<const bssl::ParsedCertificate> certificate,
-    std::vector<ChromeRootCertConstraints> constraints,
-    bool eutl,
     bool enforce_anchor_expiry,
     bool enforce_anchor_constraints)
     : certificate(std::move(certificate)),
       constraints(std::move(constraints)),
-      eutl(eutl),
       enforce_anchor_expiry(enforce_anchor_expiry),
       enforce_anchor_constraints(enforce_anchor_constraints) {}
 ChromeRootStoreData::Anchor::~Anchor() = default;
@@ -168,9 +155,9 @@
         min_version, max_version_exclusive,
         base::ToVector(constraint.permitted_dns_names()));
   }
-  return ChromeRootStoreData::Anchor(
-      std::move(parsed), std::move(constraints), anchor.eutl(),
-      anchor.enforce_anchor_expiry(), anchor.enforce_anchor_constraints());
+  return ChromeRootStoreData::Anchor(std::move(parsed), std::move(constraints),
+                                     anchor.enforce_anchor_expiry(),
+                                     anchor.enforce_anchor_constraints());
 }
 
 }  // namespace
@@ -189,6 +176,10 @@
     if (!chrome_root_store_data_anchor) {
       return std::nullopt;
     }
+    if (anchor.eutl()) {
+      root_store_data.eutl_certs_.emplace_back(
+          chrome_root_store_data_anchor.value());
+    }
     root_store_data.trust_anchors_.emplace_back(
         std::move(chrome_root_store_data_anchor.value()));
   }
@@ -200,12 +191,13 @@
     if (!chrome_root_store_data_anchor) {
       return std::nullopt;
     }
+    if (anchor.eutl()) {
+      root_store_data.eutl_certs_.emplace_back(
+          chrome_root_store_data_anchor.value());
+    }
     if (anchor.tls_trust_anchor()) {
       root_store_data.trust_anchors_.emplace_back(
           std::move(chrome_root_store_data_anchor.value()));
-    } else {
-      root_store_data.additional_certs_.emplace_back(
-          std::move(chrome_root_store_data_anchor.value()));
     }
   }
 
@@ -263,7 +255,7 @@
       cert_constraints.emplace_back(constraint);
     }
     trust_anchors_.emplace_back(std::move(parsed), std::move(cert_constraints),
-                                /*eutl=*/false, cert_info.enforce_anchor_expiry,
+                                cert_info.enforce_anchor_expiry,
                                 cert_info.enforce_anchor_constraints);
   }
 
@@ -278,9 +270,8 @@
     auto parsed = bssl::ParsedCertificate::Create(
         std::move(cert), x509_util::DefaultParseCertificateOptions(), &errors);
     CHECK(parsed);
-    additional_certs_.emplace_back(std::move(parsed),
-                                   std::vector<ChromeRootCertConstraints>(),
-                                   /*eutl=*/true);
+    eutl_certs_.emplace_back(std::move(parsed),
+                             std::vector<ChromeRootCertConstraints>());
   }
 }
 
@@ -316,15 +307,9 @@
       certificate_trust = certificate_trust.WithEnforceAnchorConstraints();
     }
     trust_store_.AddCertificate(anchor.certificate, certificate_trust);
-
-    if (anchor.eutl) {
-      eutl_trust_store_.AddTrustAnchor(anchor.certificate);
-    }
   }
-  for (const auto& anchor : root_store_data.additional_certs()) {
-    if (anchor.eutl) {
-      eutl_trust_store_.AddTrustAnchor(anchor.certificate);
-    }
+  for (const auto& anchor : root_store_data.eutl_certs()) {
+    eutl_trust_store_.AddTrustAnchor(anchor.certificate);
   }
 
   constraints_ = base::flat_map(std::move(constraints));
diff --git a/net/cert/internal/trust_store_chrome.h b/net/cert/internal/trust_store_chrome.h
index 59f0ba6e..53e2c7fc 100644
--- a/net/cert/internal/trust_store_chrome.h
+++ b/net/cert/internal/trust_store_chrome.h
@@ -83,10 +83,6 @@
            std::vector<ChromeRootCertConstraints> constraints);
     Anchor(std::shared_ptr<const bssl::ParsedCertificate> certificate,
            std::vector<ChromeRootCertConstraints> constraints,
-           bool eutl);
-    Anchor(std::shared_ptr<const bssl::ParsedCertificate> certificate,
-           std::vector<ChromeRootCertConstraints> constraints,
-           bool eutl,
            bool enforce_anchor_expiry,
            bool enforce_anchor_constraints);
     ~Anchor();
@@ -98,7 +94,6 @@
 
     std::shared_ptr<const bssl::ParsedCertificate> certificate;
     std::vector<ChromeRootCertConstraints> constraints;
-    bool eutl;
     bool enforce_anchor_expiry;
     // True if the certificate verifier should enforce X.509 constraints encoded
     // in the certificate.
@@ -129,9 +124,7 @@
   ChromeRootStoreData& operator=(ChromeRootStoreData&& other);
 
   const std::vector<Anchor>& trust_anchors() const { return trust_anchors_; }
-  const std::vector<Anchor>& additional_certs() const {
-    return additional_certs_;
-  }
+  const std::vector<Anchor>& eutl_certs() const { return eutl_certs_; }
   int64_t version() const { return version_; }
 
  private:
@@ -142,7 +135,7 @@
                       int64_t version);
 
   std::vector<Anchor> trust_anchors_;
-  std::vector<Anchor> additional_certs_;
+  std::vector<Anchor> eutl_certs_;
   int64_t version_;
 };
 
diff --git a/net/data/ssl/chrome_root_store/root_store.md b/net/data/ssl/chrome_root_store/root_store.md
index 8847b51..698f00c 100644
--- a/net/data/ssl/chrome_root_store/root_store.md
+++ b/net/data/ssl/chrome_root_store/root_store.md
@@ -1,7 +1,7 @@
 <!-- mdformat off(generated) -->
 <!-- mdlint off(generated) -->
 # Chrome Root Store
-Version: 22
+Version: 23
 
 [TOC]
 
diff --git a/net/data/ssl/chrome_root_store/root_store.textproto b/net/data/ssl/chrome_root_store/root_store.textproto
index f00653b..e068970 100644
--- a/net/data/ssl/chrome_root_store/root_store.textproto
+++ b/net/data/ssl/chrome_root_store/root_store.textproto
@@ -8,7 +8,7 @@
 
 # Version # should always be incremented up whenever this (or any pem file that
 # it references) is changed.
-version_major: 22
+version_major: 23
 
 # CN=Actalis Authentication Root CA, O=Actalis S.p.A./03358520967, L=Milan, C=IT
 # https://ssltest-a.actalis.it:8443
@@ -336,16 +336,19 @@
 # CN=GTS Root R3, O=Google Trust Services LLC, C=US
 trust_anchors {
   sha256_hex: "34d8a73ee208d9bcdb0d956520934b4e40e69482596e8b6f73c8426b010a6f48"
+  trust_anchor_id: "\xd6\x79\x09\x03"  # 11129.9.3
 }
 
 # CN=GTS Root R1, O=Google Trust Services LLC, C=US
 trust_anchors {
   sha256_hex: "d947432abde7b7fa90fc2e6b59101b1280e0e1c7e4e40fa3c6887fff57a7f4cf"
+  trust_anchor_id: "\xd6\x79\x09\x01"  # 11129.9.1
 }
 
 # CN=GTS Root R4, O=Google Trust Services LLC, C=US
 trust_anchors {
   sha256_hex: "349dfa4058c5e263123b398ae795573c4e1313c83fe68f93556cd5e8031b3c7d"
+  trust_anchor_id: "\xd6\x79\x09\x04"  # 11129.9.4
 }
 
 # CN=GlobalSign, O=GlobalSign, OU=GlobalSign ECC Root CA - R4
@@ -356,6 +359,7 @@
 # CN=GTS Root R2, O=Google Trust Services LLC, C=US
 trust_anchors {
   sha256_hex: "8d25cd97229dbf70356bda4eb3cc734031e24cf00fafcfd32dc76eb5841c7ea8"
+  trust_anchor_id: "\xd6\x79\x09\x02"  # 11129.9.2
 }
 
 # CN=Hongkong Post Root CA 3, O=Hongkong Post, L=Hong Kong, ST=Hong Kong, C=HK
diff --git a/net/device_bound_sessions/host_patterns.cc b/net/device_bound_sessions/host_patterns.cc
index a1d4a58..18a7999 100644
--- a/net/device_bound_sessions/host_patterns.cc
+++ b/net/device_bound_sessions/host_patterns.cc
@@ -4,6 +4,8 @@
 
 #include "net/device_bound_sessions/host_patterns.h"
 
+#include "url/url_util.h"
+
 namespace net::device_bound_sessions {
 
 bool IsValidHostPattern(std::string_view host_pattern) {
@@ -26,7 +28,7 @@
   }
 
   if (host_pattern.starts_with("*.") &&
-      host.ends_with(host_pattern.substr(1))) {
+      host.ends_with(host_pattern.substr(1)) && !url::HostIsIPAddress(host)) {
     return true;
   }
 
diff --git a/net/device_bound_sessions/session.cc b/net/device_bound_sessions/session.cc
index 912812b..21c3f46 100644
--- a/net/device_bound_sessions/session.cc
+++ b/net/device_bound_sessions/session.cc
@@ -10,6 +10,7 @@
 #include "base/strings/escape.h"
 #include "base/types/expected_macros.h"
 #include "components/unexportable_keys/unexportable_key_id.h"
+#include "net/base/features.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_access_params.h"
@@ -301,7 +302,9 @@
         return dict;
       });
 
-  if (!AllowedToInitiateRefresh(request->initiator())) {
+  if (base::FeatureList::IsEnabled(
+          features::kDeviceBoundSessionsOriginTrialFeedback) &&
+      !AllowedToInitiateRefresh(request->initiator())) {
     request->net_log().AddEvent(
         net::NetLogEventType::CHECK_DBSC_REFRESH_REQUIRED,
         [&](NetLogCaptureMode capture_mode) {
diff --git a/net/device_bound_sessions/session_inclusion_rules_unittest.cc b/net/device_bound_sessions/session_inclusion_rules_unittest.cc
index 3925c76a..caf85c9 100644
--- a/net/device_bound_sessions/session_inclusion_rules_unittest.cc
+++ b/net/device_bound_sessions/session_inclusion_rules_unittest.cc
@@ -446,8 +446,8 @@
   CheckAddUrlRuleTestCases(
       {// Exact host is allowed.
        {RuleType::kExclude, "4.31.198.44", "/", true},
-       // Wildcards are permitted only if they can match the origin.
-       {RuleType::kExclude, "*.31.198.44", "/", true},
+       // Wildcards are not permitted for IPv4 addresses.
+       {RuleType::kExclude, "*.31.198.44", "/", false},
        {RuleType::kExclude, "*.4.31.198.44", "/", false},
        // Other hosts with no registrable domain are not allowed.
        {RuleType::kExclude, "[1:abcd::3:4:ff]", "/", false},
diff --git a/net/device_bound_sessions/session_unittest.cc b/net/device_bound_sessions/session_unittest.cc
index 5ebf5a0..ead6a0e 100644
--- a/net/device_bound_sessions/session_unittest.cc
+++ b/net/device_bound_sessions/session_unittest.cc
@@ -7,6 +7,7 @@
 #include <string_view>
 
 #include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_inclusion_status.h"
 #include "net/cookies/cookie_util.h"
@@ -31,6 +32,16 @@
   std::unique_ptr<URLRequestContext> context_;
 };
 
+class SessionTestWithOriginTrialFeedback : public SessionTest {
+ protected:
+  SessionTestWithOriginTrialFeedback() {
+    feature_list_.InitAndEnableFeature(
+        features::kDeviceBoundSessionsOriginTrialFeedback);
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+};
+
 class FakeDelegate : public URLRequest::Delegate {
   void OnReadCompleted(URLRequest* request, int bytes_read) override {}
 };
@@ -551,6 +562,49 @@
   EXPECT_TRUE(
       session->ShouldDeferRequest(request.get(), FirstPartySetMetadata()));
 
+  // Initiators not on the site can be deferred since
+  // kDeviceBoundSessionsOriginTrialFeedback is not enabled.
+  request->set_initiator(
+      url::Origin::Create(GURL("https://some-other-not-example.test/")));
+  EXPECT_TRUE(
+      session->ShouldDeferRequest(request.get(), FirstPartySetMetadata()));
+}
+
+TEST_F(SessionTestWithOriginTrialFeedback, DeferredAllowedRefreshInitiators) {
+  auto params = CreateValidParams();
+  params.allowed_refresh_initiators = {"*.not-example.test"};
+  // We need a third-party cookie to be included on requests from other
+  // initiators.
+  params.credentials = {SessionParams::Credential{
+      "test_cookie",
+      /*attributes=*/"Secure; Domain=example.test; SameSite=None"}};
+  auto session_or_error = Session::CreateIfValid(params);
+  ASSERT_TRUE(session_or_error.has_value());
+  std::unique_ptr<Session> session = std::move(*session_or_error);
+  ASSERT_TRUE(session);
+  net::TestDelegate delegate;
+  // Create a request matching the fetcher URL.
+  std::unique_ptr<URLRequest> request =
+      context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
+  request->set_site_for_cookies(SiteForCookies::FromUrl(kTestUrl));
+
+  // Browser-initiated requests can always be deferred
+  request->set_initiator(std::nullopt);
+  EXPECT_TRUE(
+      session->ShouldDeferRequest(request.get(), FirstPartySetMetadata()));
+
+  // Initiators on the site can always be deferred, despite no matching
+  // initiator pattern.
+  request->set_initiator(url::Origin::Create(GURL("https://example.test/")));
+  EXPECT_TRUE(
+      session->ShouldDeferRequest(request.get(), FirstPartySetMetadata()));
+
+  // Initiators matching the pattern can be deferred.
+  request->set_initiator(
+      url::Origin::Create(GURL("https://subdomain.not-example.test/")));
+  EXPECT_TRUE(
+      session->ShouldDeferRequest(request.get(), FirstPartySetMetadata()));
+
   // Initiators not on the site or matching a rule cannot be deferred.
   request->set_initiator(
       url::Origin::Create(GURL("https://some-other-not-example.test/")));
@@ -763,6 +817,37 @@
   RecordingNetLogObserver net_log_observer;
   session->ShouldDeferRequest(request.get(), FirstPartySetMetadata());
 
+  // Because kDeviceBoundSessionsOriginTrialFeedback is not enabled, we will not
+  // enforce the initiators.
+  std::vector<NetLogEntry> entries = net_log_observer.GetEntriesWithType(
+      NetLogEventType::CHECK_DBSC_REFRESH_REQUIRED);
+  ASSERT_EQ(entries.size(), 1u);
+  EXPECT_EQ(*entries[0].params.FindString("refresh_required_reason"),
+            "missing_cookie");
+}
+
+TEST_F(SessionTestWithOriginTrialFeedback, NetLogWrongInitiator) {
+  auto params = CreateValidParams();
+  params.allowed_refresh_initiators = {};
+  // We need a third-party cookie to be included on requests from other
+  // initiators.
+  params.credentials = {SessionParams::Credential{
+      "test_cookie",
+      /*attributes=*/"Secure; Domain=example.test; SameSite=None"}};
+  auto session_or_error = Session::CreateIfValid(params);
+  ASSERT_TRUE(session_or_error.has_value());
+  std::unique_ptr<Session> session = std::move(*session_or_error);
+  ASSERT_TRUE(session);
+  net::TestDelegate delegate;
+  std::unique_ptr<URLRequest> request =
+      context_->CreateRequest(kTestUrl, IDLE, &delegate, kDummyAnnotation);
+  request->set_site_for_cookies(SiteForCookies::FromUrl(kTestUrl));
+  request->set_initiator(
+      url::Origin::Create(GURL("https://not-example.test/")));
+
+  RecordingNetLogObserver net_log_observer;
+  session->ShouldDeferRequest(request.get(), FirstPartySetMetadata());
+
   std::vector<NetLogEntry> entries = net_log_observer.GetEntriesWithType(
       NetLogEventType::CHECK_DBSC_REFRESH_REQUIRED);
   ASSERT_EQ(entries.size(), 1u);
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index 9e11532..6120cf9 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -1408,10 +1408,6 @@
   return true;
 }
 
-bool QuicChromiumClientSession::ShouldCreateOutgoingUnidirectionalStream() {
-  NOTREACHED() << "Try to create outgoing unidirectional streams";
-}
-
 bool QuicChromiumClientSession::WasConnectionEverUsed() {
   const quic::QuicConnectionStats& stats = connection()->GetStats();
   return stats.bytes_sent > 0 || stats.bytes_received > 0;
@@ -1423,11 +1419,6 @@
 }
 
 QuicChromiumClientStream*
-QuicChromiumClientSession::CreateOutgoingUnidirectionalStream() {
-  NOTREACHED() << "Try to create outgoing unidirectional stream";
-}
-
-QuicChromiumClientStream*
 QuicChromiumClientSession::CreateOutgoingReliableStreamImpl(
     const NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(connection()->connected());
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index 44cf6fe..5f3bd8aa 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -745,7 +745,6 @@
 
   // quic::QuicSession methods:
   QuicChromiumClientStream* CreateOutgoingBidirectionalStream() override;
-  QuicChromiumClientStream* CreateOutgoingUnidirectionalStream() override;
   const quic::QuicCryptoClientStream* GetCryptoStream() const override;
   quic::QuicCryptoClientStream* GetMutableCryptoStream() override;
   void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override;
@@ -983,7 +982,6 @@
   // quic::QuicSession methods:
   bool ShouldCreateIncomingStream(quic::QuicStreamId id) override;
   bool ShouldCreateOutgoingBidirectionalStream() override;
-  bool ShouldCreateOutgoingUnidirectionalStream() override;
 
   QuicChromiumClientStream* CreateIncomingStream(
       quic::QuicStreamId id) override;
diff --git a/net/quic/quic_session_pool.cc b/net/quic/quic_session_pool.cc
index df5ca67..fd239e0 100644
--- a/net/quic/quic_session_pool.cc
+++ b/net/quic/quic_session_pool.cc
@@ -1628,7 +1628,6 @@
     Job* job,
     std::optional<base::TimeTicks> proxy_connect_start_time,
     int rv) {
-  auto iter = active_jobs_.find(job->key().session_key());
   if (proxy_connect_start_time) {
     HttpProxyConnectJob::EmitConnectLatency(
         NextProto::kProtoQUIC, ProxyServer::Scheme::SCHEME_QUIC,
@@ -1637,7 +1636,16 @@
         base::TimeTicks::Now() - *proxy_connect_start_time);
   }
 
-  CHECK(iter != active_jobs_.end());
+  auto job_iter = active_jobs_.find(job->key().session_key());
+  CHECK(job_iter != active_jobs_.end());
+  CHECK_EQ(job_iter->second.get(), job);
+  // Remove the job so it doesn't get reused by any new requests that are
+  // added synchronously by QuicSessionRequest::OnRequestComplete() below.
+  std::unique_ptr<Job> completed_job = std::move(job_iter->second);
+  active_jobs_.erase(job_iter);
+
+  job->set_is_deleting();
+
   if (rv == OK) {
     if (!has_quic_ever_worked_on_current_network_) {
       set_has_quic_ever_worked_on_current_network(true);
@@ -1646,7 +1654,7 @@
     auto session_it = active_sessions_.find(job->key().session_key());
     CHECK(session_it != active_sessions_.end());
     QuicChromiumClientSession* session = session_it->second;
-    for (QuicSessionRequest* request : iter->second->requests()) {
+    for (QuicSessionRequest* request : job->requests()) {
       // Do not notify |request| yet.
       request->SetSession(session->CreateHandle(job->key().destination()));
     }
@@ -1654,7 +1662,7 @@
     NotifyOnConnectionFailure(job->key().session_key());
   }
 
-  for (QuicSessionRequest* request : iter->second->requests()) {
+  for (QuicSessionRequest* request : job->requests()) {
     // Even though we're invoking callbacks here, we don't need to worry
     // about |this| being deleted, because the pool is owned by the
     // profile which can not be deleted via callbacks.
@@ -1663,7 +1671,6 @@
     }
     request->OnRequestComplete(rv);
   }
-  active_jobs_.erase(iter);
 }
 
 bool QuicSessionPool::HasActiveSession(
diff --git a/net/quic/quic_session_pool_job.cc b/net/quic/quic_session_pool_job.cc
index fc8824da..ea69aa8 100644
--- a/net/quic/quic_session_pool_job.cc
+++ b/net/quic/quic_session_pool_job.cc
@@ -4,6 +4,7 @@
 
 #include "net/quic/quic_session_pool_job.h"
 
+#include "base/debug/dump_without_crashing.h"
 #include "base/memory/weak_ptr.h"
 #include "base/trace_event/trace_event.h"
 #include "net/base/completion_once_callback.h"
@@ -60,6 +61,13 @@
 }
 
 void QuicSessionPool::Job::AddRequest(QuicSessionRequest* request) {
+  // We suspect that requests are being added to jobs that are being deleted
+  // which would leave the requests orphaned.
+  // TODO(crbug.com/404586727): Remove once we confirm the crash no longer
+  // happens.
+  if (is_deleting_) {
+    base::debug::DumpWithoutCrashing();
+  }
   request->AddedToJob();
   requests_.insert(request);
   SetRequestExpectations(request);
diff --git a/net/quic/quic_session_pool_job.h b/net/quic/quic_session_pool_job.h
index c7d7132f..65154b9 100644
--- a/net/quic/quic_session_pool_job.h
+++ b/net/quic/quic_session_pool_job.h
@@ -71,6 +71,10 @@
   void AssociateWithNetLogSource(
       const NetLogWithSource& http_stream_job_net_log) const;
 
+  // TODO(crbug.com/404586727): Remove once we confirm the crash no longer
+  // happens.
+  void set_is_deleting() { is_deleting_ = true; }
+
   // QuicSessionAttempt::Delegate implementation.
   QuicSessionPool* GetQuicSessionPool() override;
   const QuicSessionAliasKey& GetKey() override;
@@ -93,6 +97,9 @@
   RequestPriority priority_;
   const NetLogWithSource net_log_;
   std::set<raw_ptr<QuicSessionRequest, SetExperimental>> requests_;
+
+ private:
+  bool is_deleting_ = false;
 };
 
 }  // namespace net
diff --git a/net/quic/quic_session_pool_proxy_job_unittest.cc b/net/quic/quic_session_pool_proxy_job_unittest.cc
index 74a60f0..0d97d00 100644
--- a/net/quic/quic_session_pool_proxy_job_unittest.cc
+++ b/net/quic/quic_session_pool_proxy_job_unittest.cc
@@ -5,12 +5,16 @@
 #include <memory>
 
 #include "base/strings/strcat.h"
+#include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/run_until.h"
+#include "net/base/net_errors.h"
 #include "net/base/network_anonymization_key.h"
 #include "net/base/privacy_mode.h"
 #include "net/base/proxy_chain.h"
 #include "net/base/proxy_server.h"
 #include "net/base/session_usage.h"
+#include "net/base/test_completion_callback.h"
 #include "net/cert/x509_certificate.h"
 #include "net/quic/address_utils.h"
 #include "net/quic/crypto/proof_verifier_chromium.h"
@@ -21,6 +25,7 @@
 #include "net/quic/quic_socket_data_provider.h"
 #include "net/quic/quic_test_packet_maker.h"
 #include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
 #include "net/test/test_data_directory.h"
 #include "net/third_party/quiche/src/quiche/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
@@ -646,4 +651,111 @@
   EXPECT_TRUE(socket_data.AllDataConsumed());
 }
 
+// Regression test for crbug.com/404586727.
+TEST_P(QuicSessionPoolProxyJobTest, RequestSessionAgainInCallback) {
+  Initialize();
+
+  GURL url("https://www.example.org/");
+  GURL proxy(kProxy1Url);
+  auto origin = url::SchemeHostPort(url);
+  auto proxy_origin = url::SchemeHostPort(proxy);
+  auto nak = NetworkAnonymizationKey();
+
+  scoped_refptr<X509Certificate> cert(
+      ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
+  ASSERT_TRUE(cert->VerifyNameMatch(origin.host()));
+  ASSERT_TRUE(cert->VerifyNameMatch(proxy_origin.host()));
+  ASSERT_FALSE(cert->VerifyNameMatch(kDifferentHostname));
+
+  ProofVerifyDetailsChromium verify_details;
+  verify_details.cert_verify_result.verified_cert = cert;
+  verify_details.cert_verify_result.is_issued_by_known_root = true;
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+  // QUIC proxies do not use priority header.
+  client_maker_.set_use_priority_header(false);
+
+  // Use a separate packet maker for the connection to the endpoint.
+  QuicTestPacketMaker endpoint_maker =
+      MakePacketMaker(origin.host(), quic::Perspective::IS_CLIENT,
+                      /*client_priority_uses_incremental=*/true,
+                      /*use_priority_header=*/true);
+
+  QuicSocketDataProvider failing_request_socket_data(version_);
+  failing_request_socket_data
+      .AddWriteError("write_error", ERR_ADDRESS_UNREACHABLE)
+      .Sync();
+  socket_factory_->AddSocketDataProvider(&failing_request_socket_data);
+
+  // Add a second data provider for the second request.
+  QuicSocketDataProvider successful_request_socket_data(version_);
+  const uint64_t kStreamId = GetNthClientInitiatedBidirectionalStreamId(0);
+  successful_request_socket_data
+      .AddWrite("initial-settings", ConstructInitialSettingsPacket(1))
+      .Sync();
+  successful_request_socket_data
+      .AddWrite("connect-udp",
+                ConstructConnectUdpRequestPacket(
+                    2, kStreamId, proxy.host(),
+                    "/.well-known/masque/udp/www.example.org/443/", false))
+      .Sync();
+  successful_request_socket_data.AddRead("server-settings",
+                                         ConstructServerSettingsPacket(3));
+  successful_request_socket_data.AddRead(
+      "ok-response", ConstructOkResponsePacket(4, kStreamId, true));
+  successful_request_socket_data.AddWrite(
+      "ack", client_maker_.Packet(3).AddAckFrame(3, 4, 3).Build());
+  successful_request_socket_data.AddWrite(
+      "endpoint-initial-settings",
+      ConstructClientH3DatagramPacket(
+          4, kStreamId, kConnectUdpContextId,
+          endpoint_maker.MakeInitialSettingsPacket(1)));
+  socket_factory_->AddSocketDataProvider(&successful_request_socket_data);
+
+  auto proxy_chain = ProxyChain::ForIpProtection({
+      ProxyServer::FromSchemeHostAndPort(ProxyServer::SCHEME_QUIC,
+                                         proxy.host_piece(), 443),
+  });
+  ASSERT_TRUE(proxy_chain.IsValid());
+
+  // Second request which will be made synchronously after the failing request
+  // below finishes.
+  RequestBuilder successful_request_builder(this);
+  successful_request_builder.destination = origin;
+  successful_request_builder.proxy_chain = proxy_chain;
+  successful_request_builder.http_user_agent_settings =
+      &http_user_agent_settings_;
+  successful_request_builder.url = url;
+  TestCompletionCallback successful_callback;
+  successful_request_builder.callback = successful_callback.callback();
+
+  base::RunLoop run_loop;
+  // Failing request which will make the above request synchronously when its
+  // callback runs.
+  RequestBuilder failing_request_builder(this);
+  failing_request_builder.destination = origin;
+  failing_request_builder.proxy_chain = proxy_chain;
+  failing_request_builder.http_user_agent_settings = &http_user_agent_settings_;
+  failing_request_builder.url = url;
+  failing_request_builder.callback =
+      base::BindLambdaForTesting([&](int result) {
+        EXPECT_THAT(result, IsError(ERR_QUIC_HANDSHAKE_FAILED));
+        EXPECT_THAT(successful_request_builder.CallRequest(),
+                    IsError(ERR_IO_PENDING));
+        run_loop.Quit();
+      });
+
+  EXPECT_THAT(failing_request_builder.CallRequest(), IsError(ERR_IO_PENDING));
+  run_loop.Run();
+
+  EXPECT_THAT(successful_callback.WaitForResult(), IsOk());
+  std::unique_ptr<HttpStream> stream =
+      CreateStream(&successful_request_builder.request);
+  EXPECT_TRUE(stream.get());
+
+  // Verify the second request is successful.
+  EXPECT_TRUE(base::test::RunUntil(
+      [&]() { return successful_request_socket_data.AllDataConsumed(); }));
+}
+
 }  // namespace net::test
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 3bb8317..0af8196 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -36,7 +36,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "crypto/rsa_private_key.h"
 #include "net/base/address_list.h"
 #include "net/base/completion_once_callback.h"
 #include "net/base/features.h"
@@ -5534,11 +5533,8 @@
   bssl::UniquePtr<EVP_PKEY> pkey =
       key_util::LoadEVP_PKEYFromPEM(certs_dir.AppendASCII("ok_cert.pem"));
   ASSERT_TRUE(pkey);
-  std::unique_ptr<crypto::RSAPrivateKey> key =
-      crypto::RSAPrivateKey::CreateFromKey(pkey.get());
-  ASSERT_TRUE(key);
   std::unique_ptr<SSLServerContext> server_context =
-      CreateSSLServerContext(cert.get(), *key.get(), GetServerConfig());
+      CreateSSLServerContext(cert.get(), pkey.get(), GetServerConfig());
 
   // Complete the SSL handshake on both sides.
   std::unique_ptr<SSLClientSocket> client(CreateSSLClientSocket(
@@ -5621,17 +5617,11 @@
   ASSERT_THAT(client_callback.GetResult(client_rv), IsOk());
 
   // Set up a pair of SSL servers.
-  std::unique_ptr<crypto::RSAPrivateKey> ok_key =
-      crypto::RSAPrivateKey::CreateFromKey(ok_pkey.get());
-  ASSERT_TRUE(ok_key);
   std::unique_ptr<SSLServerContext> ok_server_context =
-      CreateSSLServerContext(ok_cert.get(), *ok_key.get(), SSLServerConfig());
+      CreateSSLServerContext(ok_cert.get(), ok_pkey.get(), SSLServerConfig());
 
-  std::unique_ptr<crypto::RSAPrivateKey> expired_key =
-      crypto::RSAPrivateKey::CreateFromKey(expired_pkey.get());
-  ASSERT_TRUE(expired_key);
   std::unique_ptr<SSLServerContext> expired_server_context =
-      CreateSSLServerContext(expired_cert.get(), *expired_key.get(),
+      CreateSSLServerContext(expired_cert.get(), expired_pkey.get(),
                              SSLServerConfig());
 
   // Complete the proxy SSL handshake with ok_cert.pem. This should succeed.
diff --git a/net/ssl/ssl_platform_key_mac_unittest.cc b/net/ssl/ssl_platform_key_mac_unittest.cc
index 58a036a0..acb98de0 100644
--- a/net/ssl/ssl_platform_key_mac_unittest.cc
+++ b/net/ssl/ssl_platform_key_mac_unittest.cc
@@ -17,8 +17,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/numerics/checked_math.h"
 #include "base/test/task_environment.h"
+#include "crypto/apple/scoped_fake_keychain_v2.h"
 #include "crypto/evp.h"
-#include "crypto/scoped_fake_apple_keychain_v2.h"
 #include "crypto/signature_verifier.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/ssl_private_key_test_util.h"
@@ -159,7 +159,7 @@
 // Tests that a SSLPrivateKey can be created from a
 // crypto::UnexportableSigningKey.
 TEST(UnexportableSSLPlatformKeyMacTest, Convert) {
-  crypto::ScopedFakeAppleKeychainV2 scoped_fake_apple_keychain_{
+  crypto::apple::ScopedFakeKeychainV2 scoped_fake_apple_keychain_{
       kTestKeychainAccessGroup};
   // Create a crypto::UnexportableSigningKey and verify preconditions.
   std::unique_ptr<crypto::UnexportableKeyProvider> provider =
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src
index 12f9083..d76b2b7 160000
--- a/net/third_party/quiche/src
+++ b/net/third_party/quiche/src
@@ -1 +1 @@
-Subproject commit 12f908334b43ea03b9d43cdd29249aecab4fb9c8
+Subproject commit d76b2b7a880bef5cb6d440f679788f82d7c3f7a0
diff --git a/pdf/pdfium/pdfium_on_demand_searchifier.cc b/pdf/pdfium/pdfium_on_demand_searchifier.cc
index a5aaba4..a4527ee 100644
--- a/pdf/pdfium/pdfium_on_demand_searchifier.cc
+++ b/pdf/pdfium/pdfium_on_demand_searchifier.cc
@@ -89,7 +89,7 @@
       // Assume OCR cannot be used anymore if it gets disconnected while
       // waiting for results. Therefore cancel all pending requests and move
       // to failed state.
-      current_page_ = nullptr;
+      ClearCurrentPage();
       pages_queue_.clear();
       state_ = State::kFailed;
       engine_->OnSearchifyStateChange(/*busy=*/false);
@@ -228,10 +228,7 @@
     }
   }
 
-  if (!current_page_was_loaded_) {
-    engine_->MaybeUnloadPage(current_page_->index());
-  }
-  current_page_ = nullptr;
+  ClearCurrentPage();
 
   // Searchify next page.
   // If none of the scheduled pages are visible, post the task with more delay
@@ -276,4 +273,11 @@
   SearchifyNextImage();
 }
 
+void PDFiumOnDemandSearchifier::ClearCurrentPage() {
+  if (current_page_ && !current_page_was_loaded_) {
+    engine_->MaybeUnloadPage(current_page_->index());
+  }
+  current_page_ = nullptr;
+}
+
 }  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_on_demand_searchifier.h b/pdf/pdfium/pdfium_on_demand_searchifier.h
index 6743d0ac..2fb5ca0a 100644
--- a/pdf/pdfium/pdfium_on_demand_searchifier.h
+++ b/pdf/pdfium/pdfium_on_demand_searchifier.h
@@ -37,8 +37,8 @@
   bool IsPageScheduled(int page_index) const;
 
   // Puts a page in the queue to be searchified. This function can be called
-  // before `Start` and if so, the page stays in the queue until searchifier
-  // starts.
+  // before `Start` and if so, the page stays in the queue until `Start` is
+  // called.
   void SchedulePage(int page_index);
 
   bool HasFailed() const { return state_ == State::kFailed; }
@@ -54,6 +54,10 @@
 
   void CommitResultsToPage();
 
+  // Resets `current_page_` and tries to unload the page if it was not loaded
+  // before `SearchifyNextPage` gets the page.
+  void ClearCurrentPage();
+
   struct BitmapResult {
     SkBitmap bitmap;
     int image_index;
diff --git a/remoting/base/compound_buffer_unittest.cc b/remoting/base/compound_buffer_unittest.cc
index 869d7c34..6833bc7 100644
--- a/remoting/base/compound_buffer_unittest.cc
+++ b/remoting/base/compound_buffer_unittest.cc
@@ -16,6 +16,7 @@
 #include <string>
 
 #include "base/containers/heap_array.h"
+#include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "net/base/io_buffer.h"
@@ -93,7 +94,7 @@
   // Iterate over chunks of data with sizes specified in |sizes| in the
   // interval [0..kDataSize]. |function| is called for each chunk.
   void IterateOverPieces(
-      const int sizes[],
+      base::span<const int> sizes,
       const base::RepeatingCallback<void(int, int)>& function) {
     DCHECK_GT(sizes[0], 0);
 
diff --git a/remoting/codec/video_encoder_vpx.cc b/remoting/codec/video_encoder_vpx.cc
index ac136d8..42fa5766 100644
--- a/remoting/codec/video_encoder_vpx.cc
+++ b/remoting/codec/video_encoder_vpx.cc
@@ -11,6 +11,7 @@
 
 #include <utility>
 
+#include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -507,7 +508,7 @@
 
 void VideoEncoderVpx::UpdateRegionFromActiveMap(
     webrtc::DesktopRegion* updated_region) {
-  const uint8_t* map = active_map_.data();
+  base::span<const uint8_t> map = active_map_;
   for (int y = 0; y < active_map_size_.height(); ++y) {
     for (int x0 = 0; x0 < active_map_size_.width();) {
       int x1 = x0;
diff --git a/remoting/host/host_secret.cc b/remoting/host/host_secret.cc
index 81b24a4..258e820 100644
--- a/remoting/host/host_secret.cc
+++ b/remoting/host/host_secret.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <string_view>
+
 #ifdef UNSAFE_BUFFERS_BUILD
 // TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
 #pragma allow_unsafe_buffers
@@ -24,7 +26,7 @@
 // should be enough for short-term passwords, given that we rate-limit guesses
 // in the cloud and expire access codes after a small number of attempts.
 const int kHostSecretLength = 5;
-const char kHostSecretAlphabet[] = "0123456789";
+const std::string_view kHostSecretAlphabet = "0123456789";
 
 // Generates cryptographically strong random number in the range [0, max).
 int CryptoRandomInt(int max) {
@@ -37,7 +39,7 @@
 
 std::string GenerateSupportHostSecret() {
   std::string result;
-  int alphabet_size = strlen(kHostSecretAlphabet);
+  int alphabet_size = strlen(kHostSecretAlphabet.data());
   result.resize(kHostSecretLength);
   for (int i = 0; i < kHostSecretLength; ++i) {
     result[i] = kHostSecretAlphabet[CryptoRandomInt(alphabet_size)];
diff --git a/remoting/host/linux/unicode_to_keysym.cc b/remoting/host/linux/unicode_to_keysym.cc
index d4c5e1d4..8f31282 100644
--- a/remoting/host/linux/unicode_to_keysym.cc
+++ b/remoting/host/linux/unicode_to_keysym.cc
@@ -10,7 +10,9 @@
 #include "remoting/host/linux/unicode_to_keysym.h"
 
 #include <algorithm>
+#include <array>
 
+#include "base/containers/span.h"
 #include "ui/gfx/x/keysyms/keysyms.h"
 
 namespace remoting {
@@ -27,7 +29,8 @@
 // value (e.g. see XK_Tab and XK_KP_Tab). It excludes Latin1 characters (which
 // have 1-to-1 mapping between keysym and unicode), but includes some
 // alternative keysyms for some of them (e.g. XK_KP_0 for '0').
-const CodePair kKeySymUnicodeMap[] = {
+// clang-format off
+const auto kKeySymUnicodeMap = std::to_array<CodePair>({
   { XK_BackSpace,                   0x0008 },
   { XK_Tab,                         0x0009 },
   { XK_KP_Tab,                      0x0009 },
@@ -798,7 +801,8 @@
   { XK_Hangul_YeorinHieuh,          0x3186 },
   { XK_Hangul_AraeA,                0x318d },
   { XK_Hangul_AraeAE,               0x318e },
-};
+});
+// clang-format on
 
 bool CompareCodePair(const CodePair& pair, uint32_t unicode) {
   return pair.unicode < unicode;
@@ -815,9 +819,11 @@
     keysyms.push_back(unicode);
   }
 
-  const CodePair* map_end = kKeySymUnicodeMap + std::size(kKeySymUnicodeMap);
-  const CodePair* pair =
-      std::lower_bound(kKeySymUnicodeMap, map_end, unicode, &CompareCodePair);
+  const CodePair* map_end = base::span<const CodePair>(kKeySymUnicodeMap)
+                                .subspan(std::size(kKeySymUnicodeMap))
+                                .data();
+  const CodePair* pair = std::lower_bound(kKeySymUnicodeMap.data(), map_end,
+                                          unicode, &CompareCodePair);
   while (pair != map_end && pair->unicode == unicode) {
     keysyms.push_back(pair->keysym);
     ++pair;
diff --git a/remoting/host/xsession_chooser_linux.cc b/remoting/host/xsession_chooser_linux.cc
index 4d7d40b..d4c7cdd 100644
--- a/remoting/host/xsession_chooser_linux.cc
+++ b/remoting/host/xsession_chooser_linux.cc
@@ -7,6 +7,9 @@
 #pragma allow_unsafe_buffers
 #endif
 
+#include "base/containers/auto_spanification_helper.h"
+#include "base/containers/span.h"
+
 // This file implements a dialog allowing the user to pick between installed
 // X session types. It finds sessions by looking for .desktop files in
 // /etc/X11/sessions and in the xsessions folder (if any) in each XDG system
@@ -271,7 +274,8 @@
   session_search_dirs.emplace_back("/etc/X11/sessions");
 
   // Returned list is owned by GLib and should not be modified or freed.
-  const gchar* const* system_data_dirs = g_get_system_data_dirs();
+  base::span<const gchar* const> system_data_dirs =
+      UNSAFE_G_GET_SYSTEM_DATA_DIRS();
   // List is null-terminated.
   for (std::size_t i = 0; system_data_dirs[i]; ++i) {
     session_search_dirs.push_back(
diff --git a/remoting/proto/google/internal/remoting/cloud/v1alpha/session_authz_service.proto b/remoting/proto/google/internal/remoting/cloud/v1alpha/session_authz_service.proto
index 0440ff6..9d2ddeb 100644
--- a/remoting/proto/google/internal/remoting/cloud/v1alpha/session_authz_service.proto
+++ b/remoting/proto/google/internal/remoting/cloud/v1alpha/session_authz_service.proto
@@ -58,10 +58,14 @@
   string shared_secret = 2;
 
   // A token opaque to the host. The host should call ReauthorizeHost
-  // with this token after |session_reauth_token_lifetime|.
+  // with this token after |session_reauth_token_lifetime|. May be an empty
+  // string if session reauthorization is not required. In that case,
+  // |session_reauth_token_lifetime| will be 0.
   string session_reauth_token = 3;
 
-  // A duration specifying when |session_reauth_token| will expire.
+  // A duration specifying when |session_reauth_token| will expire. May be 0 if
+  // session reauthorization is not required. In that case,
+  // |session_reauth_token| will be empty.
   Duration session_reauth_token_lifetime = 4;
 
   // Policies to be applied to the host.
diff --git a/remoting/protocol/message_decoder_unittest.cc b/remoting/protocol/message_decoder_unittest.cc
index cd532118..7f82837 100644
--- a/remoting/protocol/message_decoder_unittest.cc
+++ b/remoting/protocol/message_decoder_unittest.cc
@@ -15,6 +15,7 @@
 #include <memory>
 #include <string>
 
+#include "base/containers/span.h"
 #include "base/strings/string_number_conversions.h"
 #include "remoting/proto/event.pb.h"
 #include "remoting/proto/internal.pb.h"
@@ -51,7 +52,13 @@
   memcpy(*buffer, encoded_data.c_str(), *size);
 }
 
-void SimulateReadSequence(const int read_sequence[], int sequence_size) {
+void SimulateReadSequence(base::span<const int> read_sequence,
+                          int spanification_suspected_redundant_sequence_size) {
+  // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+  // redundant in M143.
+  CHECK(static_cast<size_t>(spanification_suspected_redundant_sequence_size) ==
+            read_sequence.size(),
+        base::NotFatalUntil::M143);
   // Prepare encoded data for testing.
   int size;
   uint8_t* test_data;
@@ -71,7 +78,9 @@
     SCOPED_TRACE("Input position: " + base::NumberToString(pos));
 
     // First generate the amount to feed the decoder.
-    int read = std::min(size - pos, read_sequence[pos % sequence_size]);
+    int read = std::min(
+        size - pos,
+        read_sequence[pos % spanification_suspected_redundant_sequence_size]);
 
     // And then prepare an IOBuffer for feeding it.
     auto buffer = base::MakeRefCounted<net::IOBufferWithSize>(read);
diff --git a/remoting/protocol/session_authz_authenticator.cc b/remoting/protocol/session_authz_authenticator.cc
index 59d5e704b..9b4117823 100644
--- a/remoting/protocol/session_authz_authenticator.cc
+++ b/remoting/protocol/session_authz_authenticator.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "remoting/base/http_status.h"
+#include "remoting/base/logging.h"
 #include "remoting/base/protobuf_http_request_config.h"
 #include "remoting/base/session_authz_service_client.h"
 #include "remoting/proto/session_authz_service.h"
@@ -281,7 +282,22 @@
   if (!underlying_ || underlying_->state() != ACCEPTED) {
     return;
   }
-  DCHECK(verify_token_response_);
+  if (verify_token_response_->session_reauth_token.empty()) {
+    // Reauthorization is optional for Cloud hosts but required for Corp.
+    if (credentials_type_ == CredentialsType::CLOUD_SESSION_AUTHZ) {
+      HOST_LOG << "Reauthorization is not required for this session.";
+    } else {
+      session_authz_state_ = SessionAuthzState::FAILED;
+      session_authz_rejection_reason_ = RejectionReason::UNEXPECTED_ERROR;
+      rejection_details_ = RejectionDetails(
+          base::StringPrintf("VerifySessionTokenResponse for session id '%s' "
+                             "is missing a session reauth token.",
+                             session_id_));
+      NotifyStateChangeAfterAccepted();
+    }
+    return;
+  }
+
   reauthorizer_ = std::make_unique<SessionAuthzReauthorizer>(
       service_client_.get(), verify_token_response_->session_id,
       verify_token_response_->session_reauth_token,
diff --git a/remoting/protocol/session_authz_authenticator_unittest.cc b/remoting/protocol/session_authz_authenticator_unittest.cc
index 0e28304..b3a6972 100644
--- a/remoting/protocol/session_authz_authenticator_unittest.cc
+++ b/remoting/protocol/session_authz_authenticator_unittest.cc
@@ -72,10 +72,19 @@
   return base::test::RunOnceCallback<1>(HttpStatus::OK(), std::move(response));
 }
 
+auto RespondVerifySessionTokenWithoutReauthFields() {
+  auto response =
+      std::make_unique<internal::VerifySessionTokenResponseStruct>();
+  response->session_id = kFakeSessionId;
+  response->shared_secret = kFakeSharedSecret;
+  return base::test::RunOnceCallback<1>(HttpStatus::OK(), std::move(response));
+}
+
 class FakeClientAuthenticator : public Authenticator {
  public:
-  explicit FakeClientAuthenticator(const CreateBaseAuthenticatorCallback&
-                                       create_base_authenticator_callback);
+  FakeClientAuthenticator(
+      const CreateBaseAuthenticatorCallback& create_base_authenticator_callback,
+      CredentialsType credentials_type);
   ~FakeClientAuthenticator() override;
 
   // Authenticator implementation.
@@ -112,6 +121,7 @@
       SessionAuthzState::WAITING_FOR_HOST_TOKEN;
   RejectionReason session_authz_rejection_reason_;
   CreateBaseAuthenticatorCallback create_base_authenticator_callback_;
+  CredentialsType credentials_type_ = CredentialsType::CORP_SESSION_AUTHZ;
   std::unique_ptr<Authenticator> underlying_;
   std::string host_token_;
   std::unique_ptr<jingle_xmpp::XmlElement> message_;
@@ -120,7 +130,7 @@
 };
 
 CredentialsType FakeClientAuthenticator::credentials_type() const {
-  return CredentialsType::CORP_SESSION_AUTHZ;
+  return credentials_type_;
 }
 
 const Authenticator& FakeClientAuthenticator::implementing_authenticator()
@@ -146,8 +156,10 @@
 }
 
 FakeClientAuthenticator::FakeClientAuthenticator(
-    const CreateBaseAuthenticatorCallback& create_base_authenticator_callback)
-    : create_base_authenticator_callback_(create_base_authenticator_callback) {}
+    const CreateBaseAuthenticatorCallback& create_base_authenticator_callback,
+    CredentialsType credentials_type)
+    : create_base_authenticator_callback_(create_base_authenticator_callback),
+      credentials_type_(credentials_type) {}
 
 FakeClientAuthenticator::~FakeClientAuthenticator() = default;
 
@@ -238,6 +250,10 @@
  protected:
   void SetUp() override;
 
+  // Used to create a paired set of authenticators using the provided
+  // |credentials_type|.
+  void ConfigureAuthenticators(CredentialsType credentials_type);
+
   // Caller must add an expectation for
   // mock_service_client_->GenerateHostToken() and run the callback, otherwise
   // this method will not return.
@@ -253,17 +269,23 @@
 
 void SessionAuthzAuthenticatorTest::SetUp() {
   AuthenticatorTestBase::SetUp();
+  ConfigureAuthenticators(CredentialsType::CORP_SESSION_AUTHZ);
+}
+
+void SessionAuthzAuthenticatorTest::ConfigureAuthenticators(
+    CredentialsType credentials_type) {
   auto mock_service_client = std::make_unique<MockSessionAuthzServiceClient>();
   mock_service_client_ = mock_service_client.get();
   auto host_authenticator = std::make_unique<SessionAuthzAuthenticator>(
-      CredentialsType::CORP_SESSION_AUTHZ, std::move(mock_service_client),
+      credentials_type, std::move(mock_service_client),
       base::BindRepeating(&Spake2Authenticator::CreateForHost, kHostId,
                           kClientId, host_cert_, key_pair_));
   host_authenticator_ = host_authenticator.get();
   host_ = std::move(host_authenticator);
-  auto client_authenticator =
-      std::make_unique<FakeClientAuthenticator>(base::BindRepeating(
-          &Spake2Authenticator::CreateForClient, kClientId, kHostId));
+  auto client_authenticator = std::make_unique<FakeClientAuthenticator>(
+      base::BindRepeating(&Spake2Authenticator::CreateForClient, kClientId,
+                          kHostId),
+      credentials_type);
   client_authenticator_ = client_authenticator.get();
   client_ = std::move(client_authenticator);
 }
@@ -409,6 +431,38 @@
   ASSERT_NE(host_->state(), Authenticator::ACCEPTED);
 }
 
+TEST_F(SessionAuthzAuthenticatorTest,
+       SessionReauthToken_NotPresent_AllowedForCloudHost) {
+  ConfigureAuthenticators(CredentialsType::CLOUD_SESSION_AUTHZ);
+  EXPECT_CALL(*mock_service_client_, GenerateHostToken(_))
+      .WillOnce(RespondGenerateHostToken());
+  EXPECT_CALL(*mock_service_client_, VerifySessionToken(_, _))
+      .WillOnce(RespondVerifySessionTokenWithoutReauthFields());
+
+  StartAuthExchange();
+
+  ASSERT_EQ(host_->state(), Authenticator::ACCEPTED);
+}
+
+TEST_F(SessionAuthzAuthenticatorTest,
+       SessionReauthToken_NotPresent_NotAllowedForCorpHost) {
+  ConfigureAuthenticators(CredentialsType::CORP_SESSION_AUTHZ);
+  auto response =
+      std::make_unique<internal::VerifySessionTokenResponseStruct>();
+  response->session_id = kFakeSessionId;
+  response->shared_secret = kFakeSharedSecret;
+  EXPECT_CALL(*mock_service_client_, GenerateHostToken(_))
+      .WillOnce(RespondGenerateHostToken());
+  EXPECT_CALL(*mock_service_client_, VerifySessionToken(_, _))
+      .WillOnce(RespondVerifySessionTokenWithoutReauthFields());
+
+  StartAuthExchange();
+
+  ASSERT_EQ(host_->state(), Authenticator::REJECTED);
+  ASSERT_EQ(host_->rejection_reason(),
+            Authenticator::RejectionReason::UNEXPECTED_ERROR);
+}
+
 TEST_F(SessionAuthzAuthenticatorTest, ReauthorizationFailed_Rejected) {
   EXPECT_CALL(*mock_service_client_, GenerateHostToken(_))
       .WillOnce(RespondGenerateHostToken());
diff --git a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
index c211f0e..29749d9 100644
--- a/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
+++ b/sandbox/policy/linux/sandbox_seccomp_bpf_linux.cc
@@ -216,8 +216,6 @@
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     case sandbox::mojom::Sandbox::kScreenAI:
       return std::make_unique<ScreenAIProcessPolicy>();
-    case sandbox::mojom::Sandbox::kShapeDetection:
-      return std::make_unique<UtilityProcessPolicy>();
 #if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
     case sandbox::mojom::Sandbox::kHardwareVideoDecoding:
       return std::make_unique<HardwareVideoDecodingProcessPolicy>(
@@ -243,6 +241,8 @@
       return std::make_unique<TtsProcessPolicy>();
     case sandbox::mojom::Sandbox::kNearby:
       return std::make_unique<NearbyProcessPolicy>();
+    case sandbox::mojom::Sandbox::kShapeDetection:
+      return std::make_unique<UtilityProcessPolicy>();
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
     case sandbox::mojom::Sandbox::kLibassistant:
       return std::make_unique<LibassistantProcessPolicy>();
@@ -302,12 +302,12 @@
     case sandbox::mojom::Sandbox::kIme:
     case sandbox::mojom::Sandbox::kTts:
     case sandbox::mojom::Sandbox::kNearby:
+    case sandbox::mojom::Sandbox::kShapeDetection:
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
     case sandbox::mojom::Sandbox::kLibassistant:
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
 #endif  // BUILDFLAG(IS_CHROMEOS)
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-    case sandbox::mojom::Sandbox::kShapeDetection:
     case sandbox::mojom::Sandbox::kScreenAI:
 #endif
 #if BUILDFLAG(IS_LINUX)
diff --git a/sandbox/policy/mojom/sandbox.mojom b/sandbox/policy/mojom/sandbox.mojom
index 0398ad5..0f20024 100644
--- a/sandbox/policy/mojom/sandbox.mojom
+++ b/sandbox/policy/mojom/sandbox.mojom
@@ -149,5 +149,5 @@
   [EnableIf=is_linux|is_mac] kOnDeviceTranslation,
 
   // Like kUtility but allows loading of the shape detection internal library.
-  [EnableIf=is_chromeos|is_linux] kShapeDetection,
+  [EnableIf=is_chromeos] kShapeDetection,
 };
diff --git a/sandbox/policy/sandbox_type.cc b/sandbox/policy/sandbox_type.cc
index 3e6f022..177b7f5c 100644
--- a/sandbox/policy/sandbox_type.cc
+++ b/sandbox/policy/sandbox_type.cc
@@ -65,7 +65,6 @@
 #endif
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-constexpr char kShapeDetectionSandbox[] = "shape_detection";
 // USE_LINUX_VIDEO_ACCELERATION implies IS_LINUX || IS_CHROMEOS, so this double
 // #if is redundant, however, we cannot include "media/gpu/buildflags.h" on all
 // platforms, only one those that need to evaluate the use..., hence this
@@ -80,6 +79,7 @@
 constexpr char kImeSandbox[] = "ime";
 constexpr char kTtsSandbox[] = "tts";
 constexpr char kNearbySandbox[] = "nearby";
+constexpr char kShapeDetectionSandbox[] = "shape_detection";
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
 constexpr char kLibassistantSandbox[] = "libassistant";
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
@@ -147,7 +147,6 @@
     case Sandbox::kWindowsSystemProxyResolver:
 #endif  // BUILDFLAG(IS_WIN)
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-    case Sandbox::kShapeDetection:
 #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION)
     case Sandbox::kHardwareVideoDecoding:
     case Sandbox::kHardwareVideoEncoding:
@@ -157,6 +156,7 @@
     case Sandbox::kIme:
     case Sandbox::kTts:
     case Sandbox::kNearby:
+    case Sandbox::kShapeDetection:
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
     case Sandbox::kLibassistant:
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
@@ -294,8 +294,6 @@
       return kMirroringSandbox;
 #endif
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-    case Sandbox::kShapeDetection:
-      return kShapeDetectionSandbox;
 #if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
     case Sandbox::kHardwareVideoDecoding:
       return kHardwareVideoDecodingSandbox;
@@ -312,6 +310,8 @@
       return kTtsSandbox;
     case Sandbox::kNearby:
       return kNearbySandbox;
+    case Sandbox::kShapeDetection:
+      return kShapeDetectionSandbox;
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
     case Sandbox::kLibassistant:
       return kLibassistantSandbox;
@@ -418,9 +418,6 @@
   }
 #endif
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-  if (sandbox_string == kShapeDetectionSandbox) {
-    return Sandbox::kShapeDetection;
-  }
 #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION)
   if (sandbox_string == kHardwareVideoDecodingSandbox) {
     return Sandbox::kHardwareVideoDecoding;
@@ -440,6 +437,9 @@
   if (sandbox_string == kNearbySandbox) {
     return Sandbox::kNearby;
   }
+  if (sandbox_string == kShapeDetectionSandbox) {
+    return Sandbox::kShapeDetection;
+  }
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
   if (sandbox_string == kLibassistantSandbox) {
     return Sandbox::kLibassistant;
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 3b658cc..22cd9aa 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -73,6 +73,16 @@
       bundle_deps =
           [ "//services/tracing:services_tracing_perfetto_bundle_data" ]
     }
+    if (is_android) {
+      deps += [
+        # The java target is added explicitly because the unit tests below
+        # require connection to the Java classes. Without a direct dependency,
+        # the unit tests will encounter a ClassNotFoundException error at
+        # runtime.
+        "//services/on_device_model/android:java",
+        "//services/on_device_model/android:unit_tests",
+      ]
+    }
   }
 
   if (is_android && (current_cpu == "arm" || current_cpu == "arm64")) {
diff --git a/services/media_session/public/cpp/media_image_android.cc b/services/media_session/public/cpp/media_image_android.cc
index ff75922..c50be8f 100644
--- a/services/media_session/public/cpp/media_image_android.cc
+++ b/services/media_session/public/cpp/media_image_android.cc
@@ -31,7 +31,7 @@
     ScopedJavaLocalRef<jobject> item = images[i].CreateJavaObject(env);
     env->SetObjectArrayElement(joa, i, item.obj());
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa);
 }
 
 ScopedJavaLocalRef<jobject> MediaImage::CreateJavaObject(JNIEnv* env) const {
@@ -53,8 +53,8 @@
     env->SetObjectArrayElement(joa, i, item.obj());
   }
 
-  return Java_MediaImage_create(env, j_src, j_type,
-                                ScopedJavaLocalRef<jobjectArray>(env, joa));
+  return Java_MediaImage_create(
+      env, j_src, j_type, ScopedJavaLocalRef<jobjectArray>::Adopt(env, joa));
 }
 
 }  // namespace media_session
diff --git a/services/media_session/public/cpp/test/mock_media_session.cc b/services/media_session/public/cpp/test/mock_media_session.cc
index 355d33c..088c67c 100644
--- a/services/media_session/public/cpp/test/mock_media_session.cc
+++ b/services/media_session/public/cpp/test/mock_media_session.cc
@@ -308,8 +308,7 @@
 }
 
 void MockMediaSessionMojoObserver::StartWaiting() {
-  DCHECK(!run_loop_);
-
+  CHECK(!run_loop_);
   run_loop_ = std::make_unique<base::RunLoop>();
   run_loop_->Run();
   run_loop_.reset();
@@ -421,11 +420,13 @@
 }
 
 void MockMediaSession::EnterPictureInPicture() {
-  // TODO(crbug.com/40113959): Implement EnterPictureinpicture.
+  is_in_picture_in_picture_ = true;
+  NotifyObservers();
 }
 
 void MockMediaSession::ExitPictureInPicture() {
-  // TODO(crbug.com/40113959): Implement ExitPictureinpicture.
+  is_in_picture_in_picture_ = false;
+  NotifyObservers();
 }
 
 void MockMediaSession::GetVisibility(GetVisibilityCallback callback) {
@@ -578,8 +579,9 @@
 void MockMediaSession::NotifyObservers() {
   mojom::MediaSessionInfoPtr session_info = GetMediaSessionInfoSync();
 
-  if (afr_client_.is_bound())
+  if (afr_client_.is_bound()) {
     afr_client_->MediaSessionInfoChanged(session_info.Clone());
+  }
 
   for (auto& observer : observers_) {
     observer->MediaSessionInfoChanged(session_info.Clone());
@@ -599,6 +601,10 @@
 
   info->is_controllable = is_controllable_;
   info->prefer_stop_for_gain_focus_loss = prefer_stop_;
+  info->picture_in_picture_state =
+      (is_in_picture_in_picture_
+           ? mojom::MediaPictureInPictureState::kInPictureInPicture
+           : mojom::MediaPictureInPictureState::kNotInPictureInPicture);
 
   return info;
 }
diff --git a/services/media_session/public/cpp/test/mock_media_session.h b/services/media_session/public/cpp/test/mock_media_session.h
index c1070af..9bf87d00 100644
--- a/services/media_session/public/cpp/test/mock_media_session.h
+++ b/services/media_session/public/cpp/test/mock_media_session.h
@@ -247,6 +247,7 @@
   bool is_controllable_ = false;
   bool is_scrubbing_ = false;
   bool prefer_stop_ = false;
+  bool is_in_picture_in_picture_ = false;
 
   int prev_track_count_ = 0;
   int next_track_count_ = 0;
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 62f7668e..fab694a 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -6160,7 +6160,6 @@
 TEST_F(NetworkContextTest, GetHSTSState) {
   const char kTestDomain[] = "example.com";
   const base::Time expiry = base::Time::Now() + base::Seconds(1000);
-  const GURL report_uri = GURL("https://example.com/foo/bar");
 
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateNetworkContextParamsForTesting());
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index 91148be..e4dab2326 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -221,8 +221,7 @@
 // This feature is being built as a replacement for Private Network Access
 // (PNA), and if this is on PNA features may stop working.
 //
-// Public explainer:
-// https://github.com/explainers-by-googlers/local-network-access
+// Spec: https://wicg.github.io/local-network-access/
 BASE_FEATURE(kLocalNetworkAccessChecks,
              "LocalNetworkAccessChecks",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -238,8 +237,7 @@
 // Blocks local network requests without user permission to prevent exploitation
 // of vulnerable local devices.
 //
-// Public explainer:
-// https://github.com/explainers-by-googlers/local-network-access
+// Spec: https://wicg.github.io/local-network-access/
 BASE_FEATURE(kLocalNetworkAccessChecksWebRTC,
              "LocalNetworkAccessChecksWebRTC",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/services/network/public/mojom/client_security_state.mojom b/services/network/public/mojom/client_security_state.mojom
index 3d3be9a..01fd2b1 100644
--- a/services/network/public/mojom/client_security_state.mojom
+++ b/services/network/public/mojom/client_security_state.mojom
@@ -22,10 +22,10 @@
 // See the definition in the Private Network Access(PNA) specification:
 // https://wicg.github.io/private-network-access/#ip-address-space
 //
-// Note: work is being done to move from the PNA specification to LNA.
+// Note: work is being done to move from the PNA specification to Local Network
+// Access (LNA).
 //
-// Explainer:
-// https://github.com/explainers-by-googlers/local-network-access
+// LNA Spec: https://wicg.github.io/local-network-access/
 enum PrivateNetworkRequestPolicy {
   // Allow the requests.
   kAllow,
diff --git a/services/network/public/mojom/cors.mojom b/services/network/public/mojom/cors.mojom
index d221027e..0069984b 100644
--- a/services/network/public/mojom/cors.mojom
+++ b/services/network/public/mojom/cors.mojom
@@ -153,7 +153,7 @@
   kPrivateNetworkAccessPermissionDenied,
 
   // User did not grant permission to access the local network.
-  // See: https://github.com/explainers-by-googlers/local-network-access
+  // See: https://wicg.github.io/local-network-access/
   kLocalNetworkAccessPermissionDenied,
 };
 
diff --git a/services/network/public/mojom/ip_address_space.mojom b/services/network/public/mojom/ip_address_space.mojom
index 4eeec1b..b84d476 100644
--- a/services/network/public/mojom/ip_address_space.mojom
+++ b/services/network/public/mojom/ip_address_space.mojom
@@ -6,8 +6,7 @@
 
 // Represents AddressSpace from the "Local Network Access" spec. The ordering
 // is important, as it's used to determine whether a request is a Local Network
-// Access requests.  See:
-// https://github.com/explainers-by-googlers/local-network-access
+// Access requests.  See: https://wicg.github.io/local-network-access/
 enum IPAddressSpace {
   kLoopback, // contains the loopback device only.
 
diff --git a/services/network/public/mojom/key_pinning.mojom b/services/network/public/mojom/key_pinning.mojom
index b8087d59..b0e2ec9 100644
--- a/services/network/public/mojom/key_pinning.mojom
+++ b/services/network/public/mojom/key_pinning.mojom
@@ -14,8 +14,6 @@
   array<SHA256HashValue> static_spki_hashes;
   // Optional set of forbidden SPKIs hashes
   array<SHA256HashValue> bad_static_spki_hashes;
-  // Optional URI to send bad pin reports to.
-  string report_uri;
 };
 
 struct PinSetInfo {
diff --git a/services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom b/services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom
index 1579da2..ffd12ff 100644
--- a/services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom
+++ b/services/network/public/mojom/permissions_policy/permissions_policy_feature.mojom
@@ -319,7 +319,7 @@
   kDeviceAttributes = 135,
 
   // Allows a site to make local network access requests.
-  // See https://github.com/explainers-by-googlers/local-network-access
+  // See: https://wicg.github.io/local-network-access/
   kLocalNetworkAccess = 136,
 
   // Controls Protected Audience API's view and click functionality.
diff --git a/services/on_device_model/BUILD.gn b/services/on_device_model/BUILD.gn
index 8a21d28..29bf2c7 100644
--- a/services/on_device_model/BUILD.gn
+++ b/services/on_device_model/BUILD.gn
@@ -59,6 +59,9 @@
   if (is_linux || is_chromeos) {
     deps += [ "//gpu/config" ]
   }
+  if (is_android) {
+    deps += [ "//services/on_device_model/android" ]
+  }
   if (!is_fuchsia) {
     deps += [
       "//third_party/dawn/include/dawn:cpp_headers",
diff --git a/services/on_device_model/android/BUILD.gn b/services/on_device_model/android/BUILD.gn
new file mode 100644
index 0000000..82ac591
--- /dev/null
+++ b/services/on_device_model/android/BUILD.gn
@@ -0,0 +1,62 @@
+# 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/android/config.gni")
+import("//build/config/android/rules.gni")
+import("//third_party/jni_zero/jni_zero.gni")
+
+source_set("android") {
+  sources = [
+    "backend_impl_android.cc",
+    "backend_impl_android.h",
+    "backend_model_impl_android.cc",
+    "backend_model_impl_android.h",
+    "backend_session_impl_android.cc",
+    "backend_session_impl_android.h",
+    "on_device_model_bridge.cc",
+    "on_device_model_bridge.h",
+  ]
+
+  deps = [
+    ":jni_headers",
+    "//base",
+    "//mojo/public/cpp/bindings",
+    "//services/on_device_model:backend_interfaces",
+    "//services/on_device_model/public/cpp",
+    "//services/on_device_model/public/mojom",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "backend_impl_android_unittest.cc" ]
+  deps = [
+    ":android",
+    "//base/test:test_support",
+    "//services/on_device_model/public/cpp/test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+android_library("java") {
+  sources = [
+    "java/src/org/chromium/on_device_model/AiCoreSession.java",
+    "java/src/org/chromium/on_device_model/AiCoreSessionFactory.java",
+    "java/src/org/chromium/on_device_model/AiCoreSessionUpstreamImpl.java",
+    "java/src/org/chromium/on_device_model/OnDeviceModelBridge.java",
+  ]
+  deps = [
+    "//base:base_java",
+    "//base:service_loader_java",
+    "//third_party/jni_zero:jni_zero_java",
+  ]
+  srcjar_deps = [ ":jni_headers" ]
+}
+
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/on_device_model/AiCoreSession.java",
+    "java/src/org/chromium/on_device_model/OnDeviceModelBridge.java",
+  ]
+}
diff --git a/services/on_device_model/android/backend_impl_android.cc b/services/on_device_model/android/backend_impl_android.cc
new file mode 100644
index 0000000..e0fb24a
--- /dev/null
+++ b/services/on_device_model/android/backend_impl_android.cc
@@ -0,0 +1,53 @@
+// 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 "services/on_device_model/android/backend_impl_android.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/functional/callback.h"
+#include "base/notimplemented.h"
+#include "base/types/expected.h"
+#include "services/on_device_model/android/backend_model_impl_android.h"
+#include "services/on_device_model/public/cpp/service_client.h"
+#include "services/on_device_model/public/mojom/on_device_model.mojom.h"
+
+namespace on_device_model {
+
+BackendImplAndroid::BackendImplAndroid() = default;
+
+BackendImplAndroid::~BackendImplAndroid() = default;
+
+base::expected<void, ServiceDisconnectReason> BackendImplAndroid::CanCreate() {
+  return base::ok();
+}
+
+Capabilities BackendImplAndroid::GetCapabilities(ModelFile model_file) {
+  NOTIMPLEMENTED();
+  return {};
+}
+
+base::expected<std::unique_ptr<BackendModel>, mojom::LoadModelResult>
+BackendImplAndroid::CreateWithResult(mojom::LoadModelParamsPtr params,
+                                     base::OnceClosure on_complete) {
+  auto model = std::make_unique<BackendModelImplAndroid>();
+  // `on_complete` record metrics, so it is called after the model is created to
+  // include the time to create the model.
+  std::move(on_complete).Run();
+  return base::ok(std::move(model));
+}
+
+void BackendImplAndroid::LoadTextSafetyModel(
+    mojom::TextSafetyModelParamsPtr params,
+    mojo::PendingReceiver<mojom::TextSafetyModel> model) {
+  NOTIMPLEMENTED();
+}
+
+mojom::DevicePerformanceInfoPtr BackendImplAndroid::GetDevicePerformanceInfo() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+}  // namespace on_device_model
diff --git a/services/on_device_model/android/backend_impl_android.h b/services/on_device_model/android/backend_impl_android.h
new file mode 100644
index 0000000..86214b9
--- /dev/null
+++ b/services/on_device_model/android/backend_impl_android.h
@@ -0,0 +1,33 @@
+// 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 SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_IMPL_ANDROID_H_
+#define SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_IMPL_ANDROID_H_
+
+#include "services/on_device_model/backend.h"
+
+namespace on_device_model {
+
+// Android implementation of Backend. Since the base model is not directly
+// managed by Chrome, only `CreateWithResult` is implemented.
+class BackendImplAndroid : public Backend {
+ public:
+  BackendImplAndroid();
+  ~BackendImplAndroid() override;
+
+  // Backend:
+  base::expected<void, ServiceDisconnectReason> CanCreate() override;
+  Capabilities GetCapabilities(ModelFile model_file) override;
+  base::expected<std::unique_ptr<BackendModel>, mojom::LoadModelResult>
+  CreateWithResult(mojom::LoadModelParamsPtr params,
+                   base::OnceClosure on_complete) override;
+  void LoadTextSafetyModel(
+      mojom::TextSafetyModelParamsPtr params,
+      mojo::PendingReceiver<mojom::TextSafetyModel> model) override;
+  mojom::DevicePerformanceInfoPtr GetDevicePerformanceInfo() override;
+};
+
+}  // namespace on_device_model
+
+#endif  // SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_IMPL_ANDROID_H_
diff --git a/services/on_device_model/android/backend_impl_android_unittest.cc b/services/on_device_model/android/backend_impl_android_unittest.cc
new file mode 100644
index 0000000..65103a8
--- /dev/null
+++ b/services/on_device_model/android/backend_impl_android_unittest.cc
@@ -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.
+
+#include "services/on_device_model/android/backend_impl_android.h"
+
+#include "base/test/task_environment.h"
+#include "services/on_device_model/public/cpp/test_support/test_response_holder.h"
+#include "services/on_device_model/public/mojom/on_device_model.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace on_device_model {
+namespace {
+
+using ::testing::ElementsAre;
+
+class BackendImplAndroidTest : public testing::Test {
+ public:
+  BackendImplAndroidTest() = default;
+  ~BackendImplAndroidTest() override = default;
+
+ protected:
+  base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(BackendImplAndroidTest, Generate) {
+  BackendImplAndroid backend;
+  auto model_result = backend.CreateWithResult(
+      /*params=*/nullptr, /*on_complete=*/base::DoNothing());
+  ASSERT_TRUE(model_result.has_value());
+  std::unique_ptr<BackendModel> model = std::move(model_result.value());
+
+  std::unique_ptr<BackendSession> session =
+      model->CreateSession(/*adaptation=*/nullptr, /*params=*/nullptr);
+
+  TestResponseHolder response_holder;
+  session->Generate(mojom::GenerateOptions::New(), response_holder.BindRemote(),
+                    /*on_complete=*/base::DoNothing());
+  response_holder.WaitForCompletion();
+  EXPECT_THAT(response_holder.responses(), ElementsAre("AiCore response"));
+}
+
+}  // namespace
+}  // namespace on_device_model
diff --git a/services/on_device_model/android/backend_model_impl_android.cc b/services/on_device_model/android/backend_model_impl_android.cc
new file mode 100644
index 0000000..41ed65c
--- /dev/null
+++ b/services/on_device_model/android/backend_model_impl_android.cc
@@ -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.
+
+#include "services/on_device_model/android/backend_model_impl_android.h"
+
+#include <memory>
+
+#include "base/notimplemented.h"
+#include "services/on_device_model/android/backend_session_impl_android.h"
+
+namespace on_device_model {
+
+BackendModelImplAndroid::BackendModelImplAndroid() = default;
+
+BackendModelImplAndroid::~BackendModelImplAndroid() = default;
+
+std::unique_ptr<BackendSession> BackendModelImplAndroid::CreateSession(
+    const ScopedAdaptation* adaptation,
+    on_device_model::mojom::SessionParamsPtr params) {
+  return std::make_unique<BackendSessionImplAndroid>();
+}
+
+std::unique_ptr<BackendModel::ScopedAdaptation>
+BackendModelImplAndroid::LoadAdaptation(
+    on_device_model::mojom::LoadAdaptationParamsPtr params) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void BackendModelImplAndroid::UnloadAdaptation(uint32_t adaptation_id) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace on_device_model
diff --git a/services/on_device_model/android/backend_model_impl_android.h b/services/on_device_model/android/backend_model_impl_android.h
new file mode 100644
index 0000000..bff5aff
--- /dev/null
+++ b/services/on_device_model/android/backend_model_impl_android.h
@@ -0,0 +1,30 @@
+// 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 SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_MODEL_IMPL_ANDROID_H_
+#define SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_MODEL_IMPL_ANDROID_H_
+
+#include "base/memory/weak_ptr.h"
+#include "services/on_device_model/backend_model.h"
+
+namespace on_device_model {
+
+// Uses the OnDeviceModel APIs that are available on Android to create sessions.
+class BackendModelImplAndroid : public BackendModel {
+ public:
+  BackendModelImplAndroid();
+  ~BackendModelImplAndroid() override;
+
+  // BackendModel:
+  std::unique_ptr<BackendSession> CreateSession(
+      const ScopedAdaptation* adaptation,
+      on_device_model::mojom::SessionParamsPtr params) override;
+  std::unique_ptr<ScopedAdaptation> LoadAdaptation(
+      on_device_model::mojom::LoadAdaptationParamsPtr params) override;
+  void UnloadAdaptation(uint32_t adaptation_id) override;
+};
+
+}  // namespace on_device_model
+
+#endif  // SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_MODEL_IMPL_ANDROID_H_
diff --git a/services/on_device_model/android/backend_session_impl_android.cc b/services/on_device_model/android/backend_session_impl_android.cc
new file mode 100644
index 0000000..80571e21
--- /dev/null
+++ b/services/on_device_model/android/backend_session_impl_android.cc
@@ -0,0 +1,100 @@
+// 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 "services/on_device_model/android/backend_session_impl_android.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/functional/callback.h"
+#include "base/notimplemented.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/on_device_model/android/on_device_model_bridge.h"
+#include "services/on_device_model/public/mojom/on_device_model.mojom.h"
+
+// Must come after all headers that specialize FromJniType() / ToJniType().
+#include "services/on_device_model/android/jni_headers/AiCoreSession_jni.h"
+
+namespace on_device_model {
+
+BackendSessionImplAndroid::BackendSessionImplAndroid()
+    : java_session_(OnDeviceModelBridge::CreateSession()) {}
+
+BackendSessionImplAndroid::~BackendSessionImplAndroid() = default;
+
+void BackendSessionImplAndroid::Append(
+    on_device_model::mojom::AppendOptionsPtr options,
+    mojo::PendingRemote<on_device_model::mojom::ContextClient> client,
+    base::OnceClosure on_complete) {
+  NOTIMPLEMENTED();
+  std::move(on_complete).Run();
+}
+
+void BackendSessionImplAndroid::Generate(
+    on_device_model::mojom::GenerateOptionsPtr input,
+    mojo::PendingRemote<on_device_model::mojom::StreamingResponder> response,
+    base::OnceClosure on_complete) {
+  responder_.Bind(std::move(response));
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  // TODO(crbug.com/425408635): Pass the real input.
+  base::android::ScopedJavaLocalRef<jstring> j_input =
+      base::android::ConvertUTF8ToJavaString(env, "");
+  Java_AiCoreSession_generate(env, java_session_,
+                              reinterpret_cast<intptr_t>(this), j_input);
+  std::move(on_complete).Run();
+}
+
+void BackendSessionImplAndroid::SizeInTokens(
+    on_device_model::mojom::InputPtr input,
+    base::OnceCallback<void(uint32_t)> callback) {
+  NOTIMPLEMENTED();
+  std::move(callback).Run(0);
+}
+
+void BackendSessionImplAndroid::Score(
+    const std::string& text,
+    base::OnceCallback<void(float)> callback) {
+  NOTIMPLEMENTED();
+  std::move(callback).Run(0.0f);
+}
+
+void BackendSessionImplAndroid::GetProbabilitiesBlocking(
+    const std::string& input,
+    base::OnceCallback<void(const std::vector<float>&)> callback) {
+  NOTIMPLEMENTED();
+  std::move(callback).Run({});
+}
+
+std::unique_ptr<BackendSession> BackendSessionImplAndroid::Clone() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void BackendSessionImplAndroid::OnResponse(const std::string& response) {
+  auto chunk = on_device_model::mojom::ResponseChunk::New();
+  chunk->text = response;
+  responder_->OnResponse(std::move(chunk));
+}
+
+void BackendSessionImplAndroid::OnComplete() {
+  responder_->OnComplete(on_device_model::mojom::ResponseSummary::New());
+}
+
+void JNI_AiCoreSession_OnComplete(JNIEnv* env, jlong backend_session) {
+  reinterpret_cast<BackendSessionImplAndroid*>(backend_session)->OnComplete();
+}
+
+void JNI_AiCoreSession_OnResponse(
+    JNIEnv* env,
+    jlong backend_session,
+    const jni_zero::JavaParamRef<jstring>& j_response) {
+  reinterpret_cast<BackendSessionImplAndroid*>(backend_session)
+      ->OnResponse(base::android::ConvertJavaStringToUTF8(env, j_response));
+}
+
+}  // namespace on_device_model
diff --git a/services/on_device_model/android/backend_session_impl_android.h b/services/on_device_model/android/backend_session_impl_android.h
new file mode 100644
index 0000000..4b175d1
--- /dev/null
+++ b/services/on_device_model/android/backend_session_impl_android.h
@@ -0,0 +1,58 @@
+// 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 SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_SESSION_IMPL_ANDROID_H_
+#define SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_SESSION_IMPL_ANDROID_H_
+
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/on_device_model/backend_session.h"
+
+namespace on_device_model {
+
+// Android implementation of BackendSession. A Java counterpart with the same
+// lifetime will be created when this object is created.
+class BackendSessionImplAndroid : public BackendSession {
+ public:
+  BackendSessionImplAndroid();
+  ~BackendSessionImplAndroid() override;
+
+  // BackendSession:
+  void Append(on_device_model::mojom::AppendOptionsPtr options,
+              mojo::PendingRemote<on_device_model::mojom::ContextClient> client,
+              base::OnceClosure on_complete) override;
+  void Generate(
+      on_device_model::mojom::GenerateOptionsPtr input,
+      mojo::PendingRemote<on_device_model::mojom::StreamingResponder> response,
+      base::OnceClosure on_complete) override;
+  void SizeInTokens(on_device_model::mojom::InputPtr input,
+                    base::OnceCallback<void(uint32_t)> callback) override;
+  void Score(const std::string& text,
+             base::OnceCallback<void(float)> callback) override;
+  void GetProbabilitiesBlocking(
+      const std::string& input,
+      base::OnceCallback<void(const std::vector<float>&)> callback) override;
+  std::unique_ptr<BackendSession> Clone() override;
+
+  // Called by Java:
+  // Called when the response of `Generate` is received from the AiCoreSession.
+  void OnResponse(const std::string& response);
+  // Called when the response of `Generate` is completed from the AiCoreSession.
+  void OnComplete();
+
+ private:
+  // The Java counterpart of this object.
+  base::android::ScopedJavaGlobalRef<jobject> java_session_;
+
+  // The responder to use for the current `Generate` call. Only storing one
+  // responder is fine because `Generate` is only called until the previous one
+  // completes.
+  mojo::Remote<on_device_model::mojom::StreamingResponder> responder_;
+};
+
+}  // namespace on_device_model
+
+#endif  // SERVICES_ON_DEVICE_MODEL_ANDROID_BACKEND_SESSION_IMPL_ANDROID_H_
diff --git a/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSession.java b/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSession.java
new file mode 100644
index 0000000..b1b4cc3b
--- /dev/null
+++ b/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSession.java
@@ -0,0 +1,34 @@
+// 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.on_device_model;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.JNINamespace;
+import org.jni_zero.NativeMethods;
+
+import org.chromium.build.annotations.NullMarked;
+
+/** A session that uses AiCore to generate output. */
+@JNINamespace("on_device_model")
+@NullMarked
+interface AiCoreSession {
+    /**
+     * Request AiCore to generate text. Response will be delivered via the native callback
+     * (onResponse and onComplete).
+     *
+     * @param nativeBackendSession The pointer to the native BackendSession. Used to deliver the
+     *     result back to the native side.
+     * @param input The input text.
+     */
+    @CalledByNative
+    void generate(long nativeBackendSession, String input);
+
+    @NativeMethods
+    interface Natives {
+        void onComplete(long backendSession);
+
+        void onResponse(long backendSession, String response);
+    }
+}
diff --git a/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSessionFactory.java b/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSessionFactory.java
new file mode 100644
index 0000000..71de8b3
--- /dev/null
+++ b/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSessionFactory.java
@@ -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.
+
+package org.chromium.on_device_model;
+
+import org.chromium.build.annotations.NullMarked;
+
+/**
+ * A factory to create AiCoreSession. This is null when the AiCore API is not available. Downstream
+ * code may provide a different factory via the @ServiceImpl annotation.
+ */
+@NullMarked
+public interface AiCoreSessionFactory {
+    AiCoreSession createSession();
+}
diff --git a/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSessionUpstreamImpl.java b/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSessionUpstreamImpl.java
new file mode 100644
index 0000000..96eadd01
--- /dev/null
+++ b/services/on_device_model/android/java/src/org/chromium/on_device_model/AiCoreSessionUpstreamImpl.java
@@ -0,0 +1,18 @@
+// 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.on_device_model;
+
+import org.chromium.build.annotations.NullMarked;
+
+/** A dummy implementation of AiCoreSession. Used when AiCore is not available. */
+@NullMarked
+class AiCoreSessionUpstreamImpl implements AiCoreSession {
+    @Override
+    public void generate(long nativeBackendSession, String input) {
+        // TODO(crbug.com/425408635): Return an error instead.
+        AiCoreSessionJni.get().onResponse(nativeBackendSession, "AiCore response");
+        AiCoreSessionJni.get().onComplete(nativeBackendSession);
+    }
+}
diff --git a/services/on_device_model/android/java/src/org/chromium/on_device_model/OnDeviceModelBridge.java b/services/on_device_model/android/java/src/org/chromium/on_device_model/OnDeviceModelBridge.java
new file mode 100644
index 0000000..0afa6bc
--- /dev/null
+++ b/services/on_device_model/android/java/src/org/chromium/on_device_model/OnDeviceModelBridge.java
@@ -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.
+
+package org.chromium.on_device_model;
+
+import org.jni_zero.CalledByNative;
+import org.jni_zero.JNINamespace;
+
+import org.chromium.base.ServiceLoaderUtil;
+import org.chromium.build.annotations.NullMarked;
+
+/**
+ * A central bridge to connect between the native and java code for on-device model. Responsible
+ * for: 1) creating and managing the AiCoreSession on java side. 2) forwarding the request from the
+ * native side to the AiCoreSession. 3) forwarding the response from the AiCoreSession to the native
+ * side.
+ */
+@JNINamespace("on_device_model")
+@NullMarked
+class OnDeviceModelBridge {
+    /**
+     * Creates a new AiCoreSession.
+     *
+     * @return The AiCoreSession instance.
+     */
+    @CalledByNative
+    private static AiCoreSession createSession() {
+        AiCoreSessionFactory factory = ServiceLoaderUtil.maybeCreate(AiCoreSessionFactory.class);
+        if (factory == null) {
+            return new AiCoreSessionUpstreamImpl();
+        }
+        return factory.createSession();
+    }
+}
diff --git a/services/on_device_model/android/on_device_model_bridge.cc b/services/on_device_model/android/on_device_model_bridge.cc
new file mode 100644
index 0000000..7bb9687
--- /dev/null
+++ b/services/on_device_model/android/on_device_model_bridge.cc
@@ -0,0 +1,22 @@
+// 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 "services/on_device_model/android/on_device_model_bridge.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+
+// Must come after all headers that specialize FromJniType() / ToJniType().
+#include "services/on_device_model/android/jni_headers/OnDeviceModelBridge_jni.h"
+
+namespace on_device_model {
+
+// static
+base::android::ScopedJavaLocalRef<jobject>
+OnDeviceModelBridge::CreateSession() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_OnDeviceModelBridge_createSession(env);
+}
+
+}  // namespace on_device_model
diff --git a/services/on_device_model/android/on_device_model_bridge.h b/services/on_device_model/android/on_device_model_bridge.h
new file mode 100644
index 0000000..897d2be
--- /dev/null
+++ b/services/on_device_model/android/on_device_model_bridge.h
@@ -0,0 +1,23 @@
+// 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 SERVICES_ON_DEVICE_MODEL_ANDROID_ON_DEVICE_MODEL_BRIDGE_H_
+#define SERVICES_ON_DEVICE_MODEL_ANDROID_ON_DEVICE_MODEL_BRIDGE_H_
+
+#include "base/android/scoped_java_ref.h"
+
+namespace on_device_model {
+
+// A static bridge to connect between the native and java code for on-device
+// model.
+class OnDeviceModelBridge {
+ public:
+  // Creates a new AiCoreSession instance. Caller is responsible for
+  // creating a global ref if it needs to be stored.
+  static base::android::ScopedJavaLocalRef<jobject> CreateSession();
+};
+
+}  // namespace on_device_model
+
+#endif  // SERVICES_ON_DEVICE_MODEL_ANDROID_ON_DEVICE_MODEL_BRIDGE_H_
diff --git a/services/on_device_model/on_device_model_service.cc b/services/on_device_model/on_device_model_service.cc
index b5b81c5..52bd8cd 100644
--- a/services/on_device_model/on_device_model_service.cc
+++ b/services/on_device_model/on_device_model_service.cc
@@ -26,6 +26,10 @@
 #include "services/on_device_model/public/cpp/features.h"
 #include "services/on_device_model/public/cpp/service_client.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "services/on_device_model/android/backend_impl_android.h"
+#endif
+
 namespace on_device_model {
 namespace {
 
@@ -406,15 +410,19 @@
   model_->AddSession(std::move(session), session_->Clone(), priority_);
 }
 
-const ml::ChromeML* DefaultImpl() {
+std::unique_ptr<Backend> DefaultImpl() {
+#if BUILDFLAG(IS_ANDROID)
+  return std::make_unique<BackendImplAndroid>();
+#else
   if (base::FeatureList::IsEnabled(features::kUseFakeChromeML)) {
-    return fake_ml::GetFakeChromeML();
+    return std::make_unique<ml::BackendImpl>(fake_ml::GetFakeChromeML());
   }
 #if defined(ENABLE_ML_INTERNAL)
-  return ::ml::ChromeML::Get();
+  return std::make_unique<ml::BackendImpl>(::ml::ChromeML::Get());
 #else
-  return fake_ml::GetFakeChromeML();
-#endif
+  return std::make_unique<ml::BackendImpl>(fake_ml::GetFakeChromeML());
+#endif  // defined(ENABLE_ML_INTERNAL)
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 }  // namespace
@@ -437,7 +445,7 @@
     mojo::PendingReceiver<mojom::OnDeviceModelService> receiver,
     std::unique_ptr<Backend> backend) {
   if (!backend) {
-    backend = std::make_unique<ml::BackendImpl>(DefaultImpl());
+    backend = DefaultImpl();
   }
   RETURN_IF_ERROR(backend->CanCreate(),
                   [&](ServiceDisconnectReason reason)
diff --git a/services/shape_detection/BUILD.gn b/services/shape_detection/BUILD.gn
index 5f5f4a71..30d0bc2 100644
--- a/services/shape_detection/BUILD.gn
+++ b/services/shape_detection/BUILD.gn
@@ -104,7 +104,7 @@
 
   if (is_android) {
     deps += [ ":shape_detection_jni_headers" ]
-  } else if (is_chromeos || is_linux) {
+  } else if (is_chromeos) {
     sources += [
       "shape_detection_sandbox_hook.cc",
       "shape_detection_sandbox_hook.h",
diff --git a/services/shape_detection/features.gni b/services/shape_detection/features.gni
index 3248a558..11c5139 100644
--- a/services/shape_detection/features.gni
+++ b/services/shape_detection/features.gni
@@ -6,7 +6,7 @@
 import("//build/config/compiler/compiler.gni")
 
 declare_args() {
-  if (is_chrome_branded && (is_chromeos || is_linux)) {
+  if (is_chrome_branded && is_chromeos) {
     build_with_internal_shape_detection = true
   } else {
     build_with_internal_shape_detection = false
diff --git a/services/shape_detection/public/mojom/BUILD.gn b/services/shape_detection/public/mojom/BUILD.gn
index b782b9a..8c50bc1 100644
--- a/services/shape_detection/public/mojom/BUILD.gn
+++ b/services/shape_detection/public/mojom/BUILD.gn
@@ -21,9 +21,8 @@
     "//ui/gfx/geometry/mojom",
   ]
 
-  # On branded ChromeOS and Linux, shape detection is hosted in a utility
-  # process. Other platforms host it in the GPU process.
-  if ((is_linux || is_chromeos) && is_chrome_branded) {
+  # Platforms except Chrome OS host shape detection in the GPU process.
+  if (is_chromeos && is_chrome_branded) {
     enabled_features = [ "has_shape_detection_utility" ]
   }
 }
diff --git a/services/shape_detection/shape_detection_service.cc b/services/shape_detection/shape_detection_service.cc
index 2fcd7b1..bc7957d 100644
--- a/services/shape_detection/shape_detection_service.cc
+++ b/services/shape_detection/shape_detection_service.cc
@@ -21,8 +21,7 @@
 #include "services/shape_detection/barcode_detection_provider_mac.h"
 #elif BUILDFLAG(IS_ANDROID)
 // No C++ code, barcode detection comes from Java.
-#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && \
-    (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
+#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
 #include "services/shape_detection/barcode_detection_provider_chrome.h"
 #else
 #include "services/shape_detection/barcode_detection_provider_impl.h"
@@ -55,8 +54,7 @@
       receiver.PassPipe().release().value());
 #elif BUILDFLAG(IS_MAC)
   BarcodeDetectionProviderMac::Create(std::move(receiver));
-#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && \
-    (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
+#elif BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_CHROMEOS)
   BarcodeDetectionProviderChrome::Create(std::move(receiver));
 #else
   BarcodeDetectionProviderImpl::Create(std::move(receiver));
diff --git a/services/webnn/coreml/graph_builder_coreml.cc b/services/webnn/coreml/graph_builder_coreml.cc
index c143317..8b0f143 100644
--- a/services/webnn/coreml/graph_builder_coreml.cc
+++ b/services/webnn/coreml/graph_builder_coreml.cc
@@ -1205,8 +1205,6 @@
        {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(1)},
        /*cumulative_sum_input=*/
        {kFloatsAndInt32, kMaxRank},
-       // TODO(crbug.com/396176047): Make scale and zero_point's rank match with
-       // input.
        // TODO(crbug.com/361603703): Support constant (u)int4 inputs via
        // https://apple.github.io/coremltools/source/coremltools.converters.mil.mil.ops.defs.html#coremltools.converters.mil.mil.ops.defs.iOS18.compression.constexpr_blockwise_shift_scale
        /*dequantize_linear_input=*/{kInts8Ints32, kMaxRank},
@@ -2412,19 +2410,18 @@
   // or vector scale whose size matches with one axis of input.
   base::span<const uint32_t> scale_dimensions = scale_operand_info.dimensions;
   base::span<const uint32_t> input_dimensions = input_operand_info.dimensions;
-  CHECK_LE(scale_dimensions.size(), input_dimensions.size());
+  CHECK_EQ(scale_dimensions.size(), input_dimensions.size());
   uint32_t scale_vector_size = 0;
   size_t axis = 0;
   bool has_matching_dimension = false;
   for (size_t i = 0; i < scale_dimensions.size(); ++i) {
-    size_t current_axis = input_dimensions.size() + i - scale_dimensions.size();
     if (scale_dimensions[i] != 1) {
       // Only allow at most one matching dimension, otherwise emulate.
-      if (scale_dimensions[i] != input_dimensions[current_axis] ||
+      if (scale_dimensions[i] != input_dimensions[i] ||
           has_matching_dimension) {
         return AddOperationForDequantizeLinearEmulate(operation, block);
       } else {
-        axis = current_axis;
+        axis = i;
         scale_vector_size = scale_dimensions[i];
         has_matching_dimension = true;
       }
@@ -2570,22 +2567,14 @@
   bool input_needs_reshape = input_operand_info.dimensions.empty();
   std::vector<uint32_t> input_shape = input_operand_info.dimensions;
   std::vector<uint32_t> scale_shape = scale_operand_info.dimensions;
-  CHECK_GE(input_shape.size(), scale_shape.size());
+  CHECK_EQ(input_shape.size(), scale_shape.size());
   CHECK(std::ranges::equal(scale_shape, zero_point_operand_info.dimensions));
 
   if (input_needs_reshape) {
     input_shape = {1};
+    scale_shape = {1};
   }
 
-  // TODO(crbug.com/396176047): Remove this logic after WebNN requires scale and
-  // zero_point's rank match with input.
-  if (scale_shape.size() < input_shape.size()) {
-    std::vector<uint32_t> scale_reshaped(
-        input_shape.size() - scale_shape.size(), 1);
-    scale_reshaped.insert(scale_reshaped.end(), scale_shape.begin(),
-                          scale_shape.end());
-    scale_shape = std::move(scale_reshaped);
-  }
   static constexpr char kParamOffset[] = "offset";
   RETURN_IF_ERROR(
       SetInputFromConstantOperand(*op->mutable_inputs(), kOpParamData,
@@ -2671,17 +2660,15 @@
       GetOperandInfo(input_operand_id).dimensions;
   base::span<const uint32_t> scale_dimensions =
       GetOperandInfo(scale_operand_id).dimensions;
-  CHECK_LE(scale_dimensions.size(), input_dimensions.size());
+  CHECK_EQ(scale_dimensions.size(), input_dimensions.size());
 
   // When zero_point and scale on a dimension is not
   // input_dimension or 1, this is a blockwise dequantization, the zero_point
   // and scale need to be expanded.
   for (size_t i = 0; i < scale_dimensions.size(); ++i) {
     uint32_t scale_vector_size = scale_dimensions[i];
-    size_t current_axis = input_dimensions.size() + i - scale_dimensions.size();
 
-    if (scale_vector_size != 1 &&
-        scale_vector_size != input_dimensions[current_axis]) {
+    if (scale_vector_size != 1 && scale_vector_size != input_dimensions[i]) {
       // For blockwise dequantization we need to expand the shape by 1 during
       // `ExpandDimForBlockwise`, so the original shape needs to be <=4.
       if (scale_dimensions.size() > 4) {
@@ -2689,9 +2676,8 @@
             "Unsupported rank for scale. It should "
             "be between 0 and 4 for blockwise (de)quantization.");
       }
-      CHECK_EQ(input_dimensions[current_axis] % scale_vector_size, 0u);
-      const int32_t repetitions =
-          input_dimensions[current_axis] / scale_vector_size;
+      CHECK_EQ(input_dimensions[i] % scale_vector_size, 0u);
+      const int32_t repetitions = input_dimensions[i] / scale_vector_size;
       OperandId prev_scale = scale_operand_id;
       ASSIGN_OR_RETURN(
           scale_operand_id,
@@ -4813,14 +4799,13 @@
   size_t axis = 0;
   bool has_matching_dimension = false;
   for (size_t i = 0; i < scale_dimensions.size(); ++i) {
-    size_t current_axis = input_dimensions.size() + i - scale_dimensions.size();
     if (scale_dimensions[i] != 1) {
       // Only allow at most one matching dimension, otherwise emulate.
-      if (scale_dimensions[i] != input_dimensions[current_axis] ||
+      if (scale_dimensions[i] != input_dimensions[i] ||
           has_matching_dimension) {
         return AddOperationForQuantizeLinearEmulate(operation, block);
       } else {
-        axis = current_axis;
+        axis = i;
         scale_vector_size = scale_dimensions[i];
         has_matching_dimension = true;
       }
diff --git a/services/webnn/dml/graph_impl_dml.cc b/services/webnn/dml/graph_impl_dml.cc
index 0d9b33b..a090368 100644
--- a/services/webnn/dml/graph_impl_dml.cc
+++ b/services/webnn/dml/graph_impl_dml.cc
@@ -2121,14 +2121,8 @@
                 std::is_same_v<DML_OPERATOR_DESC,
                                DML_DEQUANTIZE_OPERATOR_DESC>) {
     const auto input_rank = input_tensor_desc.GetDimensions().size();
-    // DML_QUANTIZE_OPERATOR_DESC and DML_DEQUANTIZE_OPERATOR_DESC constraint
-    // scale and zeroPoint must have the same dimension rank with input.
-    if (scale_tensor_desc.GetDimensions().size() < input_rank) {
-      scale_tensor_desc.EnsureMinimumRank(input_rank,
-                                          TensorDesc::Alignment::kTrailing);
-      zero_point_tensor_desc.EnsureMinimumRank(
-          input_rank, TensorDesc::Alignment::kTrailing);
-    }
+    const auto scale_rank = scale_tensor_desc.GetDimensions().size();
+    CHECK_EQ(scale_rank, input_rank);
 
     // A invalid parameter error will be reported from DirectML when a
     // dequantize is followed by a matmul and the input rank of the dequantize
@@ -2148,20 +2142,17 @@
   } else {
     const auto input_dimensions = input_tensor_desc.GetDimensions();
     auto scale_dimensions = scale_tensor_desc.GetDimensions();
+    CHECK_EQ(input_dimensions.size(), scale_dimensions.size());
     // When FL < 6.3, DML_ELEMENT_WISE_DEQUANTIZE_LINEAR and
     // DML_ELEMENT_WISE_QUANTIZE_LINEAR can't support block-wise.
     // For each dimension where we need to do expansion of block_size which is
     // calculated by input_dimensions[i] / scale_dimensions[i], we use reshape
     // and broadcast to emulate.
     for (size_t index = 0; index < scale_dimensions.size(); index++) {
-      if (input_dimensions[input_dimensions.size() - index - 1] !=
-              scale_dimensions[scale_dimensions.size() - index - 1] &&
-          input_dimensions[input_dimensions.size() - index - 1] != 1 &&
-          scale_dimensions[scale_dimensions.size() - index - 1] != 1) {
-        uint32_t block_size =
-            input_dimensions[input_dimensions.size() - index - 1] /
-            scale_dimensions[scale_dimensions.size() - index - 1];
-        uint32_t axis = scale_dimensions.size() - index - 1;
+      if (input_dimensions[index] != scale_dimensions[index] &&
+          input_dimensions[index] != 1 && scale_dimensions[index] != 1) {
+        uint32_t block_size = input_dimensions[index] / scale_dimensions[index];
+        uint32_t axis = index;
 
         ASSIGN_OR_RETURN(scale,
                          BlockwiseExpandAlongAxis(scale, graph_builder, axis,
diff --git a/services/webnn/ort/context_impl_ort.cc b/services/webnn/ort/context_impl_ort.cc
index 0eb3af3..58339da 100644
--- a/services/webnn/ort/context_impl_ort.cc
+++ b/services/webnn/ort/context_impl_ort.cc
@@ -22,14 +22,13 @@
     mojo::PendingReceiver<mojom::WebNNContext> receiver,
     WebNNContextProviderImpl* context_provider,
     mojom::CreateContextOptionsPtr options,
-    scoped_refptr<Environment> env,
-    scoped_refptr<SessionOptions> session_options)
+    scoped_refptr<Environment> env)
     : WebNNContextImpl(std::move(receiver),
                        context_provider,
                        GetContextProperties(),
                        std::move(options)),
       env_(std::move(env)),
-      session_options_(std::move(session_options)),
+      session_options_(SessionOptions::Create(this->options().device)),
       is_external_data_supported_(
           env_->IsExternalDataSupported(this->options().device)) {}
 
@@ -67,6 +66,14 @@
       OperandDataType::kFloat16, OperandDataType::kFloat32,
       OperandDataType::kInt64};
 
+  static constexpr SupportedDataTypes kInts4To8Int32 = {
+      OperandDataType::kInt4, OperandDataType::kUint4, OperandDataType::kUint8,
+      OperandDataType::kInt8, OperandDataType::kInt32};
+
+  static constexpr SupportedDataTypes kFloat16To32Int32 = {
+      OperandDataType::kFloat16, OperandDataType::kFloat32,
+      OperandDataType::kInt32};
+
   return ContextProperties(
       InputOperandLayout::kNchw, Resample2DAxes::kAny,
       BatchNormalizationAxis::kChannelsFirst,
@@ -94,9 +101,9 @@
        /*conv_transpose2d_bias=*/
        {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(1)},
        /*cumulative_sum_input=*/{kFloat16To32Int32To64, kMaxNonScalarRank},
-       /*dequantize_linear_input=*/{},
-       /*dequantize_linear_scale=*/{},
-       /*dequantize_linear_zero_point=*/{},
+       /*dequantize_linear_input=*/{kInts4To8Int32, kMaxRank},
+       /*dequantize_linear_scale=*/{DataTypeConstraint::kFloat16To32, kMaxRank},
+       /*dequantize_linear_zero_point=*/{kInts4To8Int32, kMaxRank},
        /*add_input=*/
        {DataTypeConstraint::kAllDataTypesAtLeast8bits, kMaxRank},
        /*sub_input=*/
@@ -164,17 +171,22 @@
        {DataTypeConstraint::kFloat16To32Ints32To64, SupportedRanks::Exactly(2)},
        /*gemm_c=*/
        {DataTypeConstraint::kFloat16To32Ints32To64, SupportedRanks::UpTo(2)},
-       /*gru_input=*/{},
-       /*gru_bias=*/{},
-       /*gru_cell_input=*/{},
-       /*gru_cell_bias=*/{},
+       /*gru_input=*/
+       {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(3)},
+       /*gru_bias=*/
+       {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(2)},
+       /*gru_cell_input=*/
+       {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(2)},
+       /*gru_cell_bias=*/
+       {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(1)},
        /*hard_sigmoid_input=*/{DataTypeConstraint::kFloat16To32, kMaxRank},
        /*hard_swish_input=*/{DataTypeConstraint::kFloat16To32, kMaxRank},
        /*instance_normalization_input=*/
        {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(4)},
        /*instance_normalization_scale=*/
        {DataTypeConstraint::kFloat16To32, SupportedRanks::Exactly(1)},
-       /*layer_normalization_input=*/{},
+       /*layer_normalization_input=*/
+       {DataTypeConstraint::kFloat16To32, kMaxRank},
        /*leaky_relu_input=*/{DataTypeConstraint::kFloat16To32, kMaxRank},
        /*linear_input=*/{DataTypeConstraint::kFloat16To32, kMaxRank},
        /*lstm_input=*/{},
@@ -188,8 +200,9 @@
        /*l2_pool2d_input=*/{DataTypeConstraint::kFloat16To32, {3, 8}},
        /*max_pool2d_input=*/{kInts8Float16To32, {3, 8}},
        /*prelu_input=*/{DataTypeConstraint::kFloat16To32Ints32To64, kMaxRank},
-       /*quantize_linear_input=*/{},
-       /*quantize_linear_zero_point=*/{},
+       /*quantize_linear_input=*/{kFloat16To32Int32, kMaxRank},
+       /*quantize_linear_zero_point=*/
+       {DataTypeConstraint::kInts4ToInts8, kMaxRank},
        /*reduce_l1_input=*/
        {kFloat16To32Int32To64, kMaxRank},
        /*reduce_l2_input=*/
diff --git a/services/webnn/ort/context_impl_ort.h b/services/webnn/ort/context_impl_ort.h
index e574e6c..f698bdd 100644
--- a/services/webnn/ort/context_impl_ort.h
+++ b/services/webnn/ort/context_impl_ort.h
@@ -26,8 +26,7 @@
   ContextImplOrt(mojo::PendingReceiver<mojom::WebNNContext> receiver,
                  WebNNContextProviderImpl* context_provider,
                  mojom::CreateContextOptionsPtr options,
-                 scoped_refptr<Environment> env,
-                 scoped_refptr<SessionOptions> session_options);
+                 scoped_refptr<Environment> env);
 
   ContextImplOrt(const WebNNContextImpl&) = delete;
   ContextImplOrt& operator=(const ContextImplOrt&) = delete;
diff --git a/services/webnn/ort/context_provider_ort.cc b/services/webnn/ort/context_provider_ort.cc
index 0ba9188..9e50269c 100644
--- a/services/webnn/ort/context_provider_ort.cc
+++ b/services/webnn/ort/context_provider_ort.cc
@@ -4,11 +4,7 @@
 
 #include "services/webnn/ort/context_provider_ort.h"
 
-#include "base/feature_list.h"
-#include "base/types/expected_macros.h"
 #include "base/win/windows_version.h"
-#include "services/webnn/ort/context_impl_ort.h"
-#include "services/webnn/ort/environment.h"
 #include "services/webnn/public/mojom/features.mojom.h"
 
 namespace webnn::ort {
@@ -20,20 +16,4 @@
          base::FeatureList::IsEnabled(mojom::features::kWebNNOnnxRuntime);
 }
 
-base::expected<std::unique_ptr<WebNNContextImpl>, mojom::ErrorPtr>
-CreateContextFromOptions(mojom::CreateContextOptionsPtr options,
-                         const gpu::GPUInfo& gpu_info,
-                         mojo::PendingReceiver<mojom::WebNNContext> receiver,
-                         WebNNContextProviderImpl* context_provider) {
-  ASSIGN_OR_RETURN(scoped_refptr<Environment> env,
-                   Environment::Create(gpu_info));
-
-  ASSIGN_OR_RETURN(scoped_refptr<SessionOptions> session_options,
-                   SessionOptions::Create(options->device));
-
-  return std::make_unique<ContextImplOrt>(std::move(receiver), context_provider,
-                                          std::move(options), std::move(env),
-                                          std::move(session_options));
-}
-
 }  // namespace webnn::ort
diff --git a/services/webnn/ort/context_provider_ort.h b/services/webnn/ort/context_provider_ort.h
index 620fd4f..2934e51b 100644
--- a/services/webnn/ort/context_provider_ort.h
+++ b/services/webnn/ort/context_provider_ort.h
@@ -5,29 +5,14 @@
 #ifndef SERVICES_WEBNN_ORT_CONTEXT_PROVIDER_ORT_H_
 #define SERVICES_WEBNN_ORT_CONTEXT_PROVIDER_ORT_H_
 
-#include "base/types/expected.h"
-#include "gpu/config/gpu_info.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom.h"
-#include "services/webnn/public/mojom/webnn_error.mojom.h"
 
 namespace webnn {
 
-class WebNNContextImpl;
-class WebNNContextProviderImpl;
-
 namespace ort {
 
 bool ShouldCreateOrtContext(const mojom::CreateContextOptions& options);
 
-// Create a WebNN context that satisfies the requested preferences in a
-// CreateContextOptions. This corresponds to the
-// ML.createContext(MLContextOptions) overload in the WebNN API.
-base::expected<std::unique_ptr<WebNNContextImpl>, mojom::ErrorPtr>
-CreateContextFromOptions(mojom::CreateContextOptionsPtr options,
-                         const gpu::GPUInfo& gpu_info,
-                         mojo::PendingReceiver<mojom::WebNNContext> receiver,
-                         WebNNContextProviderImpl* context_provider);
-
 }  // namespace ort
 
 }  // namespace webnn
diff --git a/services/webnn/ort/environment.cc b/services/webnn/ort/environment.cc
index 43a5f599..6cfe7ed 100644
--- a/services/webnn/ort/environment.cc
+++ b/services/webnn/ort/environment.cc
@@ -165,13 +165,11 @@
 }  // namespace
 
 // static
-base::expected<scoped_refptr<Environment>, mojom::ErrorPtr> Environment::Create(
+base::expected<scoped_refptr<Environment>, std::string> Environment::Create(
     const gpu::GPUInfo& gpu_info) {
   auto* platform_functions = PlatformFunctions::GetInstance();
   if (!platform_functions) {
-    return base::unexpected(mojom::Error::New(
-        mojom::Error::Code::kNotSupportedError,
-        "WebNN is not supported in this ONNX Runtime version."));
+    return base::unexpected("Failed to get ONNX Runtime platform functions.");
   }
 
   OrtLoggingLevel ort_logging_level = ORT_LOGGING_LEVEL_ERROR;
@@ -188,9 +186,7 @@
   if (ORT_CALL_FAILED(ort_api->CreateEnvWithCustomLogger(
           OrtCustomLoggingFunction, /*logger_param=*/nullptr, ort_logging_level,
           /*logid=*/"WebNN", ScopedOrtEnv::Receiver(env).get()))) {
-    return base::unexpected(
-        mojom::Error::New(mojom::Error::Code::kNotSupportedError,
-                          "Failed to create the ONNX Runtime environment."));
+    return base::unexpected("Failed to create the ONNX Runtime environment.");
   }
 
   // Get the ORT EP library path specified by `kWebNNOrtEpLibraryPathForTesting`
@@ -202,9 +198,8 @@
         base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
             switches::kWebNNOrtEpLibraryPathForTesting);
     if (base_path.empty()) {
-      return base::unexpected(mojom::Error::New(
-          mojom::Error::Code::kNotSupportedError,
-          "The specified ONNX Runtime EP library path is empty."));
+      return base::unexpected(
+          "The specified ONNX Runtime EP library path is empty.");
     }
     specified_ep_path = base_path;
   }
diff --git a/services/webnn/ort/environment.h b/services/webnn/ort/environment.h
index 940be2f6..53c4672 100644
--- a/services/webnn/ort/environment.h
+++ b/services/webnn/ort/environment.h
@@ -5,13 +5,14 @@
 #ifndef SERVICES_WEBNN_ORT_ENVIRONMENT_H_
 #define SERVICES_WEBNN_ORT_ENVIRONMENT_H_
 
+#include <string>
+
 #include "base/memory/scoped_refptr.h"
 #include "base/types/expected.h"
 #include "base/types/pass_key.h"
 #include "gpu/config/gpu_info.h"
 #include "services/webnn/ort/scoped_ort_types.h"
 #include "services/webnn/public/mojom/webnn_device.mojom.h"
-#include "services/webnn/public/mojom/webnn_error.mojom.h"
 #include "third_party/onnxruntime_headers/src/include/onnxruntime/core/session/onnxruntime_c_api.h"
 
 namespace webnn::ort {
@@ -20,7 +21,7 @@
 // It should be kept alive until all sessions using it are destroyed.
 class Environment : public base::RefCountedThreadSafe<Environment> {
  public:
-  static base::expected<scoped_refptr<Environment>, mojom::ErrorPtr> Create(
+  static base::expected<scoped_refptr<Environment>, std::string> Create(
       const gpu::GPUInfo& gpu_info);
 
   Environment(base::PassKey<Environment> pass_key, ScopedOrtEnv env);
diff --git a/services/webnn/ort/graph_builder_ort.cc b/services/webnn/ort/graph_builder_ort.cc
index 6304303f..3653cfc 100644
--- a/services/webnn/ort/graph_builder_ort.cc
+++ b/services/webnn/ort/graph_builder_ort.cc
@@ -11,6 +11,7 @@
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/types/expected_macros.h"
 #include "base/types/fixed_array.h"
 #include "services/webnn/ort/ort_data_type.h"
 #include "services/webnn/public/cpp/graph_validation_utils.h"
@@ -69,6 +70,7 @@
 constexpr base::cstring_view kOpTypeConv2d = "Conv";
 constexpr base::cstring_view kOpTypeConvTranspose2d = "ConvTranspose";
 constexpr base::cstring_view kOpTypeCumulativeSum = "CumSum";
+constexpr base::cstring_view kOpTypeDequantizeLinear = "DequantizeLinear";
 constexpr base::cstring_view kOpTypeElu = "Elu";
 constexpr base::cstring_view kOpTypeExpand = "Expand";
 constexpr base::cstring_view kOpTypeGather = "Gather";
@@ -76,14 +78,17 @@
 constexpr base::cstring_view kOpTypeGatherND = "GatherND";
 constexpr base::cstring_view kOpTypeGelu = "Gelu";
 constexpr base::cstring_view kOpTypeGemm = "Gemm";
+constexpr base::cstring_view kOpTypeGru = "GRU";
 constexpr base::cstring_view kOpTypeHardSigmoid = "HardSigmoid";
 constexpr base::cstring_view kOpTypeHardSwish = "HardSwish";
 constexpr base::cstring_view kOpTypeInstanceNormalization =
     "InstanceNormalization";
+constexpr base::cstring_view kOpTypeLayerNormalization = "LayerNormalization";
 constexpr base::cstring_view kOpTypeLeakyRelu = "LeakyRelu";
 constexpr base::cstring_view kOpTypeMatMul = "MatMul";
 constexpr base::cstring_view kOpTypePad = "Pad";
 constexpr base::cstring_view kOpTypePRelu = "PRelu";
+constexpr base::cstring_view kOpTypeQuantizeLinear = "QuantizeLinear";
 constexpr base::cstring_view kOpTypeRelu = "Relu";
 constexpr base::cstring_view kOpTypeResample2d = "Resize";
 constexpr base::cstring_view kOpTypeReshape = "Reshape";
@@ -119,18 +124,24 @@
 constexpr base::cstring_view kOpTypeReduceSumSquare = "ReduceSumSquare";
 
 // Attributes
+constexpr base::cstring_view kAttrActivations = "activations";
 constexpr base::cstring_view kAttrAlpha = "alpha";
 constexpr base::cstring_view kAttrAxis = "axis";
 constexpr base::cstring_view kAttrBeta = "beta";
+constexpr base::cstring_view kAttrBlockSize = "block_size";
 constexpr base::cstring_view kAttrCeilMode = "ceil_mode";
 constexpr base::cstring_view kAttrDilations = "dilations";
+constexpr base::cstring_view kAttrDirection = "direction";
 constexpr base::cstring_view kAttrEpsilon = "epsilon";
 constexpr base::cstring_view kAttrExclusive = "exclusive";
 constexpr base::cstring_view kAttrGroup = "group";
+constexpr base::cstring_view kAttrHiddenSize = "hidden_size";
 constexpr base::cstring_view kAttrKeepDims = "keepdims";
 constexpr base::cstring_view kAttrKernelShape = "kernel_shape";
+constexpr base::cstring_view kAttrLinearBeforeReset = "linear_before_reset";
 constexpr base::cstring_view kAttrMode = "mode";
 constexpr base::cstring_view kAttrNoopWithEmptyAxes = "noop_with_empty_axes";
+constexpr base::cstring_view kAttrNumOutputs = "num_outputs";
 constexpr base::cstring_view kAttrOutputPadding = "output_padding";
 constexpr base::cstring_view kAttrP = "p";
 constexpr base::cstring_view kAttrPads = "pads";
@@ -146,6 +157,11 @@
 constexpr base::cstring_view kToEmulate = "ToEmulate";
 constexpr base::cstring_view kUnderscore = "_";
 
+base::unexpected<mojom::ErrorPtr> NewNotSupportedError(std::string message) {
+  return base::unexpected(mojom::Error::New(
+      mojom::Error::Code::kNotSupportedError, std::move(message)));
+}
+
 std::string GetOperandName(std::string_view name, OperandId id) {
   return base::JoinString({name, base::NumberToString(id.value())},
                           kUnderscore);
@@ -294,6 +310,46 @@
   }
 }
 
+const std::vector<base::cstring_view> GetRecurrentNetworkActivations(
+    std::vector<mojom::RecurrentNetworkActivation> activations,
+    bool is_bidirectional) {
+  std::vector<base::cstring_view> activation_list;
+  for (const auto& activation : activations) {
+    switch (activation) {
+      case mojom::RecurrentNetworkActivation::kRelu:
+        activation_list.push_back("relu");
+        break;
+      case mojom::RecurrentNetworkActivation::kSigmoid:
+        activation_list.push_back("sigmoid");
+        break;
+      case mojom::RecurrentNetworkActivation::kTanh:
+        activation_list.push_back("tanh");
+        break;
+      default:
+        NOTREACHED() << "Unsupported recurrent network activation function.";
+    }
+  }
+  if (is_bidirectional) {
+    activation_list.insert(activation_list.end(), activation_list.begin(),
+                           activation_list.end());
+  }
+  return activation_list;
+}
+
+const base::cstring_view GetRecurrentNetworkDirection(
+    mojom::RecurrentNetworkDirection direction) {
+  switch (direction) {
+    case mojom::RecurrentNetworkDirection::kForward:
+      return "forward";
+    case mojom::RecurrentNetworkDirection::kBackward:
+      return "reverse";
+    case mojom::RecurrentNetworkDirection::kBoth:
+      return "bidirectional";
+    default:
+      NOTREACHED() << "Unsupported recurrent network activation direction.";
+  }
+}
+
 }  // namespace
 
 // static
@@ -339,6 +395,20 @@
                           kUnderscore);
 }
 
+std::string GraphBuilderOrt::GenerateEmulatedOpLabel(
+    base::cstring_view op_type,
+    std::string_view original_label,
+    std::string_view additional_tag) {
+  if (additional_tag.empty()) {
+    return base::JoinString({kInserted, op_type, kToEmulate, original_label},
+                            kUnderscore);
+  } else {
+    return base::JoinString(
+        {kInserted, op_type, additional_tag, kToEmulate, original_label},
+        kUnderscore);
+  }
+}
+
 std::string GraphBuilderOrt::GenerateOperandName() {
   next_operand_id_++;
   CHECK(next_operand_id_.IsValid());
@@ -393,51 +463,52 @@
 
 std::string GraphBuilderOrt::CreateInitializerForFloat(
     OperandDataType data_type,
-    base::span<const int64_t> shape,
+    base::span<const uint32_t> shape,
     float value) {
   base::CheckedNumeric<size_t> checked_operand_size =
       std::accumulate(shape.begin(), shape.end(),
                       base::CheckedNumeric<size_t>(1), std::multiplies());
   size_t operand_size = checked_operand_size.ValueOrDie();
+  base::FixedArray<int64_t> int64_shape(shape.begin(), shape.end());
   switch (data_type) {
     case OperandDataType::kFloat32: {
       base::FixedArray<float> data(operand_size, value);
-      return CreateInitializer<float>(shape, data);
+      return CreateInitializer<float>(int64_shape, data);
     }
     case OperandDataType::kFloat16: {
       base::FixedArray<uint16_t> data(operand_size,
                                       fp16_ieee_from_fp32_value(value));
-      return CreateInitializer<uint16_t>(shape, data);
+      return CreateInitializer<uint16_t>(int64_shape, data);
     }
     case OperandDataType::kInt32: {
       base::FixedArray<int32_t> data(operand_size,
                                      base::saturated_cast<int32_t>(value));
-      return CreateInitializer<int32_t>(shape, data);
+      return CreateInitializer<int32_t>(int64_shape, data);
     }
     case OperandDataType::kUint32: {
       base::FixedArray<uint32_t> data(operand_size,
                                       base::saturated_cast<uint32_t>(value));
-      return CreateInitializer<uint32_t>(shape, data);
+      return CreateInitializer<uint32_t>(int64_shape, data);
     }
     case OperandDataType::kInt64: {
       base::FixedArray<int64_t> data(operand_size,
                                      base::saturated_cast<int64_t>(value));
-      return CreateInitializer<int64_t>(shape, data);
+      return CreateInitializer<int64_t>(int64_shape, data);
     }
     case OperandDataType::kUint64: {
       base::FixedArray<uint64_t> data(operand_size,
                                       base::saturated_cast<uint64_t>(value));
-      return CreateInitializer<uint64_t>(shape, data);
+      return CreateInitializer<uint64_t>(int64_shape, data);
     }
     case OperandDataType::kInt8: {
       base::FixedArray<int8_t> data(operand_size,
                                     base::saturated_cast<int8_t>(value));
-      return CreateInitializer<int8_t>(shape, data);
+      return CreateInitializer<int8_t>(int64_shape, data);
     }
     case OperandDataType::kUint8: {
       base::FixedArray<uint8_t> data(operand_size,
                                      base::saturated_cast<uint8_t>(value));
-      return CreateInitializer<uint8_t>(shape, data);
+      return CreateInitializer<uint8_t>(int64_shape, data);
     }
     case OperandDataType::kInt4:
     case OperandDataType::kUint4: {
@@ -474,16 +545,61 @@
 
 std::string GraphBuilderOrt::CreateOneInitializer(
     OperandDataType data_type,
-    base::span<const int64_t> shape) {
+    base::span<const uint32_t> shape) {
   return CreateInitializerForFloat(data_type, shape, 1.0f);
 }
 
 std::string GraphBuilderOrt::CreateZeroInitializer(
     OperandDataType data_type,
-    base::span<const int64_t> shape) {
+    base::span<const uint32_t> shape) {
   return CreateInitializerForFloat(data_type, shape, 0.0f);
 }
 
+std::string GraphBuilderOrt::TransposeRnnWeightOrBiasLayout(
+    base::cstring_view weight_or_bias,
+    base::span<const uint32_t> permutation) {
+  size_t num_gates = permutation.size();
+
+  // Use Split operator to split the weight/bias into num_gates slices.
+  std::vector<std::string> gate_names;
+  gate_names.reserve(num_gates);
+  for (size_t i = 0; i < num_gates; i++) {
+    gate_names.push_back(GenerateOperandName());
+  }
+  constexpr int64_t axis = 1;
+  std::array<ScopedOrtOpAttr, 2> split_attrs = {
+      model_editor_.CreateAttribute(kAttrAxis, axis),
+      model_editor_.CreateAttribute(kAttrNumOutputs,
+                                    static_cast<int64_t>(num_gates))};
+  std::array<const char*, 1> split_inputs = {weight_or_bias.c_str()};
+  std::vector<const char*> split_outputs;
+  split_outputs.reserve(num_gates);
+  for (const auto& gate_name : gate_names) {
+    split_outputs.push_back(gate_name.c_str());
+  }
+  std::string split_node_name = GenerateNodeName(
+      base::JoinString({kInserted, kOpTypeSplit}, kUnderscore));
+  model_editor_.AddNode(kOpTypeSplit, split_node_name, split_inputs,
+                        split_outputs, split_attrs);
+
+  // Use Concat operator to concatenate the slices in the order of permutation.
+  std::vector<const char*> concat_inputs;
+  concat_inputs.reserve(num_gates);
+  for (uint32_t index : permutation) {
+    concat_inputs.push_back(gate_names[index].c_str());
+  }
+  std::string concat_output = GenerateOperandName();
+  std::array<const char*, 1> concat_outputs = {concat_output.c_str()};
+  std::array<ScopedOrtOpAttr, 1> concat_attrs = {
+      model_editor_.CreateAttribute(kAttrAxis, axis)};
+  std::string concat_node_name = GenerateNodeName(
+      base::JoinString({kInserted, kOpTypeConcat}, kUnderscore));
+  model_editor_.AddNode(kOpTypeConcat, concat_node_name, concat_inputs,
+                        concat_outputs, concat_attrs);
+
+  return concat_output;
+}
+
 void GraphBuilderOrt::AddCastNode(base::cstring_view node_name,
                                   base::cstring_view input,
                                   base::cstring_view output,
@@ -589,6 +705,31 @@
   model_editor_.AddNode(kOpTypeSlice, node_name, inputs, outputs);
 }
 
+void GraphBuilderOrt::AddTransposeNode(base::cstring_view node_name,
+                                       base::cstring_view input,
+                                       base::cstring_view output,
+                                       base::span<const uint32_t> perm_value) {
+  std::array<const char*, 1> inputs = {input.c_str()};
+  std::array<const char*, 1> outputs = {output.c_str()};
+
+  base::FixedArray<int64_t> perm(perm_value.begin(), perm_value.end());
+  std::array<ScopedOrtOpAttr, 1> attributes = {
+      model_editor_.CreateAttribute(kAttrPerm, perm)};
+  model_editor_.AddNode(kOpTypeTranspose, node_name, inputs, outputs,
+                        attributes);
+}
+
+std::string GraphBuilderOrt::CreateTransposeNode(
+    base::cstring_view input,
+    base::span<const uint32_t> perm_value) {
+  const std::string node_name = GenerateNodeName(
+      base::JoinString({kInserted, kOpTypeTranspose}, kUnderscore));
+  const std::string output = GenerateOperandName();
+
+  AddTransposeNode(node_name, input, output, perm_value);
+  return output;
+}
+
 std::string GraphBuilderOrt::ClampIndices(base::cstring_view indices,
                                           OperandDataType data_type,
                                           uint32_t dim_size) {
@@ -767,8 +908,7 @@
   if (input_shape.size() > 1) {
     input_channels = input_shape[1];
   }
-  std::vector<int64_t> scale_and_bias_shape = {
-      base::checked_cast<int64_t>(input_channels)};
+  std::vector<uint32_t> scale_and_bias_shape = {input_channels};
 
   // ONNX BatchNormalization requires 5 inputs: input, scale, bias, mean and
   // variance. WebNN allows optional scale/bias, so create default ones if not
@@ -929,6 +1069,108 @@
                         attributes);
 }
 
+// TODO(crbug.com/433055137): Remove the returned error once the emulation path
+// is implemented.
+template <typename T>
+  requires(std::is_same_v<T, mojom::DequantizeLinear> ||
+           std::is_same_v<T, mojom::QuantizeLinear>)
+[[nodiscard]] base::expected<void, mojom::ErrorPtr>
+GraphBuilderOrt::AddDequantizeOrQuantizeLinearOperation(
+    const T& operation,
+    base::cstring_view op_type) {
+  const std::string node_name = GenerateNodeName(operation.label);
+  std::string input = GetOperandNameById(operation.input_operand_id);
+  std::string scale = GetOperandNameById(operation.scale_operand_id);
+  std::string zero_point = GetOperandNameById(operation.zero_point_operand_id);
+  std::string output = GetOperandNameById(operation.output_operand_id);
+
+  const std::vector<uint32_t>& input_shape =
+      GetOperand(operation.input_operand_id).descriptor.shape();
+  // ZeroPoint has the same shape as the scale.
+  const std::vector<uint32_t>& scale_zero_point_shape =
+      GetOperand(operation.scale_operand_id).descriptor.shape();
+  CHECK_EQ(scale_zero_point_shape.size(), input_shape.size());
+
+  std::optional<int64_t> axis;
+  uint32_t scale_not_size_one_dimension_count = 0;
+  for (size_t i = 0; i < scale_zero_point_shape.size(); i++) {
+    if (scale_zero_point_shape[i] != 1) {
+      scale_not_size_one_dimension_count++;
+      if (scale_zero_point_shape[i] == input_shape[i]) {
+        axis = i;
+      }
+    }
+  }
+
+  // TODO(crbug.com/433096244): Emulate multiple axes case, e.g. input shape is
+  // [2, 3, 4, 5] and scale shape is [1, 3, 4, 1]. The multiple axes per-axis
+  // case will be handled by multi-dimensions blockwise emulation below.
+  bool is_per_axis =
+      axis.has_value() && scale_not_size_one_dimension_count == 1;
+
+  std::optional<int64_t> block_size;
+  if (scale_not_size_one_dimension_count == 0) {
+    // For per-tensor(per-layer) quantization and dequantization, scale should
+    // be a scalar.
+    if (!scale_zero_point_shape.empty()) {
+      // The numbers in scale shape are all 1, scale and zeroPoint should be
+      // reshaped to a scalar.
+      scale = CreateReshapeNode(scale, {});
+      zero_point = CreateReshapeNode(zero_point, {});
+    }
+  } else if (is_per_axis) {
+    // For per-axis quantization and dequantization, scale and zeroPoint should
+    // be a 1-D Tensor.
+    if (scale_zero_point_shape.size() != 1) {
+      scale = CreateReshapeNode(scale, {input_shape[axis.value()]});
+      zero_point = CreateReshapeNode(zero_point, {input_shape[axis.value()]});
+    }
+  } else {
+    // For blockwise quantization and dequantization, scale should has the same
+    // shape as the input or except for one dimension in which blocking is
+    // performed.
+    // The default values are used if scale has the same shape as the input.
+    axis = 0;
+    block_size = 1;
+    uint32_t blockwise_axis_count = 0;
+    for (size_t i = 0; i < scale_zero_point_shape.size(); i++) {
+      if (scale_zero_point_shape[i] != input_shape[i]) {
+        CHECK_EQ(input_shape[i] % scale_zero_point_shape[i], 0u);
+        block_size = input_shape[i] / scale_zero_point_shape[i];
+        axis = i;
+        blockwise_axis_count++;
+      }
+
+      // TODO(crbug.com/433096244): Emulate multi-dimensions blockwise
+      // quantization and dequantization.
+      if (blockwise_axis_count > 1) {
+        return NewNotSupportedError(
+            "For blockwise quantization and dequantization, scale should has "
+            "the same shape as the input or except for one dimension in which "
+            "blocking is performed");
+      }
+    }
+  }
+
+  std::array<const char*, 3> inputs = {input.c_str(), scale.c_str(),
+                                       zero_point.c_str()};
+  std::array<const char*, 1> outputs = {output.c_str()};
+
+  std::vector<ScopedOrtOpAttr> attributes;
+  if (axis.has_value()) {
+    attributes.push_back(
+        model_editor_.CreateAttribute(kAttrAxis, axis.value()));
+  }
+
+  if (block_size.has_value()) {
+    attributes.push_back(
+        model_editor_.CreateAttribute(kAttrBlockSize, block_size.value()));
+  }
+
+  model_editor_.AddNode(op_type, node_name, inputs, outputs, attributes);
+  return base::ok();
+}
+
 void GraphBuilderOrt::AddEluOperation(const mojom::Elu& elu) {
   const std::string node_name = GenerateNodeName(elu.label);
   std::string input = GetOperandNameById(elu.input_operand_id);
@@ -943,6 +1185,7 @@
   // node to convert the input tensor to 1-D tensor.
   // TODO(crbug.com/430960849): Remove the workaround for elu's 1D input tensor
   // limitation when the ONNX issue is fixed.
+  // https://github.com/onnx/onnx/issues/7119
   bool need_reshape = input_descriptor.Rank() != 1;
   std::vector<uint32_t> input_shape = input_descriptor.shape();
   std::string elu_output = output;
@@ -1033,8 +1276,8 @@
 void GraphBuilderOrt::AddLogicalNotEqualOperation(
     const mojom::ElementWiseBinary& not_equal) {
   // Step 1: calculate `equal(a, b)`.
-  const std::string equal_node_name = GenerateNodeName(base::JoinString(
-      {kInserted, kOpTypeEqual, kToEmulate, not_equal.label}, kUnderscore));
+  const std::string equal_node_name =
+      GenerateNodeName(GenerateEmulatedOpLabel(kOpTypeEqual, not_equal.label));
   std::string lhs = GetOperandNameById(not_equal.lhs_operand_id);
   std::string rhs = GetOperandNameById(not_equal.rhs_operand_id);
   const std::string equal_output = GenerateOperandName();
@@ -1047,9 +1290,8 @@
   // Step 2: calculate `logicalNot(equal_output)`
   const std::string not_output = GenerateOperandName();
   std::array<const char*, 1> not_outputs = {not_output.c_str()};
-  const std::string not_node_name = GenerateNodeName(base::JoinString(
-      {kInserted, kOpTypeLogicalNot, kToEmulate, not_equal.label},
-      kUnderscore));
+  const std::string not_node_name = GenerateNodeName(
+      GenerateEmulatedOpLabel(kOpTypeLogicalNot, not_equal.label));
   model_editor_.AddNode(kOpTypeLogicalNot, not_node_name, equal_outputs,
                         not_outputs);
 
@@ -1386,6 +1628,215 @@
   model_editor_.AddNode(kOpTypeGemm, node_name, inputs, outputs, attributes);
 }
 
+// `GruType` must be `mojom::Gru` or `mojom::GruCell`.
+template <typename GruType>
+  requires(std::is_same_v<GruType, mojom::Gru> ||
+           std::is_same_v<GruType, mojom::GruCell>)
+void GraphBuilderOrt::AddGruOperation(const GruType& gru) {
+  const std::string node_name = GenerateNodeName(gru.label);
+  std::string input = GetOperandNameById(gru.input_operand_id);
+  std::string weight = GetOperandNameById(gru.weight_operand_id);
+  std::string recurrent_weight =
+      GetOperandNameById(gru.recurrent_weight_operand_id);
+
+  const OperandDescriptor& input_descriptor =
+      GetOperand(gru.input_operand_id).descriptor;
+  const OperandDescriptor& weight_descriptor =
+      GetOperand(gru.weight_operand_id).descriptor;
+  const OperandDescriptor& recurrent_weight_descriptor =
+      GetOperand(gru.recurrent_weight_operand_id).descriptor;
+
+  uint32_t num_directions = 1;
+  if constexpr (std::is_same_v<GruType, mojom::Gru>) {
+    CHECK(context_properties_.data_type_limits.gru_input.Supports(
+        input_descriptor));
+    CHECK(context_properties_.data_type_limits.gru_input.Supports(
+        weight_descriptor));
+    CHECK(context_properties_.data_type_limits.gru_input.Supports(
+        recurrent_weight_descriptor));
+    num_directions =
+        gru.direction == mojom::RecurrentNetworkDirection::kBoth ? 2 : 1;
+  } else {
+    CHECK(context_properties_.data_type_limits.gru_cell_input.Supports(
+        input_descriptor));
+    CHECK(context_properties_.data_type_limits.gru_cell_input.Supports(
+        weight_descriptor));
+    CHECK(context_properties_.data_type_limits.gru_cell_input.Supports(
+        recurrent_weight_descriptor));
+
+    // Reshape the input into a 3-D tensor, since the GRU of ONNX requires
+    // the input shape to be [seq_length, batch_size, input_size]. For
+    // gruCell, `seq_length` is equal to 1.
+    const std::vector<uint32_t>& input_shape = input_descriptor.shape();
+    CHECK_EQ(input_shape.size(), 2u);
+    input = CreateReshapeNode(input, {1, input_shape[0], input_shape[1]});
+
+    // Reshape the weight into a 3-D tensor, since the GRU of ONNX requires
+    // the weight shape to be [num_directions, 3*hidden_size, input_size].
+    // For gruCell, `num_directions` is equal to 1.
+    const std::vector<uint32_t>& weight_shape = weight_descriptor.shape();
+    CHECK_EQ(weight_shape.size(), 2u);
+    weight = CreateReshapeNode(weight, {1, weight_shape[0], weight_shape[1]});
+
+    // Reshape the recurrent weight into a 3-D tensor, since the GRU of ONNX
+    // requires the recurrent weight shape to be [num_directions,
+    // 3*hidden_size, hidden_size]. For gruCell, `num_directions` is equal to 1.
+    const std::vector<uint32_t>& recurrent_weight_shape =
+        recurrent_weight_descriptor.shape();
+    CHECK_EQ(recurrent_weight_shape.size(), 2u);
+    recurrent_weight = CreateReshapeNode(
+        recurrent_weight,
+        {1, recurrent_weight_shape[0], recurrent_weight_shape[1]});
+  }
+
+  constexpr std::array<uint32_t, 3> kRznToZrnPermutation = {1, 0, 2};
+  if (gru.layout == mojom::GruWeightLayout::kRzn) {
+    weight = TransposeRnnWeightOrBiasLayout(weight, kRznToZrnPermutation);
+    recurrent_weight =
+        TransposeRnnWeightOrBiasLayout(recurrent_weight, kRznToZrnPermutation);
+  }
+
+  std::vector<const char*> inputs = {input.c_str(), weight.c_str(),
+                                     recurrent_weight.c_str()};
+
+  const uint32_t hidden_size = gru.hidden_size;
+  // Graph validation already checked that hidden_size * 3 would not overflow.
+  std::array<uint32_t, 2> bias_dims = {num_directions, hidden_size * 3};
+  std::string bias, recurrent_bias, concatenated_bias;
+  if (!gru.bias_operand_id.has_value() &&
+      !gru.recurrent_bias_operand_id.has_value()) {
+    // When both bias and recurrentBias are not present, set ONNX GRU input "B"
+    // as not specified.
+    inputs.push_back("");
+  } else {
+    if (gru.bias_operand_id.has_value()) {
+      bias = GetOperandNameById(*gru.bias_operand_id);
+      if constexpr (std::is_same_v<GruType, mojom::Gru>) {
+        CHECK(context_properties_.data_type_limits.gru_bias.Supports(
+            GetOperand(*gru.bias_operand_id).descriptor));
+      } else {
+        CHECK(context_properties_.data_type_limits.gru_cell_bias.Supports(
+            GetOperand(*gru.bias_operand_id).descriptor));
+        bias = CreateReshapeNode(bias, bias_dims);
+      }
+      if (gru.layout == mojom::GruWeightLayout::kRzn) {
+        bias = TransposeRnnWeightOrBiasLayout(bias, kRznToZrnPermutation);
+      }
+    } else {
+      bias = CreateZeroInitializer(input_descriptor.data_type(), bias_dims);
+    }
+
+    if (gru.recurrent_bias_operand_id.has_value()) {
+      recurrent_bias = GetOperandNameById(*gru.recurrent_bias_operand_id);
+      if constexpr (std::is_same_v<GruType, mojom::Gru>) {
+        CHECK(context_properties_.data_type_limits.gru_bias.Supports(
+            GetOperand(*gru.recurrent_bias_operand_id).descriptor));
+      } else {
+        CHECK(context_properties_.data_type_limits.gru_cell_bias.Supports(
+            GetOperand(*gru.recurrent_bias_operand_id).descriptor));
+        recurrent_bias = CreateReshapeNode(recurrent_bias, bias_dims);
+      }
+      if (gru.layout == mojom::GruWeightLayout::kRzn) {
+        recurrent_bias = TransposeRnnWeightOrBiasLayout(recurrent_bias,
+                                                        kRznToZrnPermutation);
+      }
+    } else {
+      recurrent_bias =
+          CreateZeroInitializer(input_descriptor.data_type(), bias_dims);
+    }
+
+    // Concat bias and recurrent_bias.
+    concatenated_bias = GenerateOperandName();
+    std::array<const char*, 2> bias_inputs = {bias.c_str(),
+                                              recurrent_bias.c_str()};
+    std::array<const char*, 1> bias_outputs = {concatenated_bias.c_str()};
+    std::array<ScopedOrtOpAttr, 1> concat_attributes = {
+        model_editor_.CreateAttribute(kAttrAxis, static_cast<int64_t>(1))};
+    std::string concat_node_name = GenerateNodeName(
+        base::JoinString({kInserted, kOpTypeConcat}, kUnderscore));
+    model_editor_.AddNode(kOpTypeConcat, concat_node_name, bias_inputs,
+                          bias_outputs, concat_attributes);
+    inputs.push_back(concatenated_bias.c_str());
+  }
+
+  // "sequence_lens" is an optional tensor specifying lengths of the sequences
+  // in a batch.
+  inputs.push_back("");
+
+  std::string hidden_state;
+  if constexpr (std::is_same_v<GruType, mojom::Gru>) {
+    if (gru.initial_hidden_state_operand_id.has_value()) {
+      hidden_state =
+          GetOperandNameById(gru.initial_hidden_state_operand_id.value());
+      CHECK(context_properties_.data_type_limits.gru_input.Supports(
+          GetOperand(gru.initial_hidden_state_operand_id.value()).descriptor));
+    }
+  } else {
+    hidden_state = GetOperandNameById(gru.hidden_state_operand_id);
+    const std::vector<uint32_t>& hidden_state_shape =
+        GetOperand(gru.hidden_state_operand_id).descriptor.shape();
+    CHECK_EQ(hidden_state_shape.size(), 2u);
+    // Reshape the hiddenState into a 3-D tensor, since the GRU of ONNX requires
+    // the "initial_h" shape to be [num_directions, batch_size, hidden_size].
+    // For gruCell, `num_directions` is equal to 1.
+    hidden_state = CreateReshapeNode(
+        hidden_state, {1, hidden_state_shape[0], hidden_state_shape[1]});
+  }
+  inputs.push_back(hidden_state.c_str());
+
+  std::vector<ScopedOrtOpAttr> attributes;
+  attributes.reserve(4);
+  base::cstring_view direction = "forward";
+  if constexpr (std::is_same_v<GruType, mojom::Gru>) {
+    direction = GetRecurrentNetworkDirection(gru.direction);
+  }
+  attributes.push_back(
+      model_editor_.CreateAttribute(kAttrDirection, direction));
+
+  const std::vector<base::cstring_view> activations =
+      GetRecurrentNetworkActivations(gru.activations,
+                                     direction == "bidirectional");
+  std::vector<const char*> activations_c_str;
+  for (const auto& activation : activations) {
+    activations_c_str.push_back(activation.c_str());
+  }
+  attributes.push_back(
+      model_editor_.CreateAttribute(kAttrActivations, activations_c_str));
+
+  attributes.push_back(model_editor_.CreateAttribute(
+      kAttrHiddenSize, base::checked_cast<int64_t>(hidden_size)));
+  attributes.push_back(model_editor_.CreateAttribute(
+      kAttrLinearBeforeReset, static_cast<int64_t>(gru.reset_after)));
+
+  std::string output, output_hidden;
+  if constexpr (std::is_same_v<GruType, mojom::Gru>) {
+    output_hidden = GetOperandNameById(gru.output_operand_ids[0]);
+    if (gru.return_sequence) {
+      output = GetOperandNameById(gru.output_operand_ids[1]);
+    }
+  } else {
+    output_hidden = GenerateOperandName();
+  }
+  std::array<const char*, 2> outputs = {output.c_str(), output_hidden.c_str()};
+  model_editor_.AddNode(kOpTypeGru, node_name, inputs, outputs, attributes);
+
+  if constexpr (std::is_same_v<GruType, mojom::GruCell>) {
+    // Reshape the ONNX GRU output "Y_h" of shape [num_directions, batch_size,
+    // hidden_size] back to a 2-D tensor, since the gruCell of WebNN requires
+    // the output shape to be [batchSize, hiddenSize].
+    const std::vector<uint32_t>& output_shape =
+        GetOperand(gru.output_operand_id).descriptor.shape();
+    CHECK_EQ(output_shape.size(), 2u);
+    InsertReshapeNode(output_hidden, GetOperandNameById(gru.output_operand_id),
+                      output_shape);
+  }
+}
+
+template void GraphBuilderOrt::AddGruOperation<mojom::Gru>(const mojom::Gru&);
+
+template void GraphBuilderOrt::AddGruOperation<mojom::GruCell>(
+    const mojom::GruCell&);
+
 void GraphBuilderOrt::AddHardSigmoidOperation(
     const mojom::HardSigmoid& hard_sigmoid) {
   const std::string node_name = GenerateNodeName(hard_sigmoid.label);
@@ -1423,11 +1874,10 @@
   // ONNX InstanceNormalization expects NCHW layout, channel is at index 1.
   CHECK_EQ(input_shape.size(), 4u);
   uint32_t input_channels = input_shape[1];
-  std::vector<int64_t> scale_and_bias_shape = {
-      base::checked_cast<int64_t>(input_channels)};
+  std::vector<uint32_t> scale_and_bias_shape = {input_channels};
 
   // ONNX InstanceNormalization requires 3 inputs: input, scale and bias.
-  // WebNN allows optional scale/bias, so create default ones if not provided
+  // WebNN allows optional scale/bias, so create default ones if not provided.
   // Default scale = 1.0 (no scaling), default bias = 0.0 (no offset).
   std::string scale, bias;
   if (instance_normalization.scale_operand_id) {
@@ -1455,6 +1905,244 @@
                         outputs, attributes);
 }
 
+void GraphBuilderOrt::AddLayerNormalizationOperation(
+    const mojom::LayerNormalization& layer_normalization) {
+  const std::string node_name = GenerateNodeName(layer_normalization.label);
+  const std::string input =
+      GetOperandNameById(layer_normalization.input_operand_id);
+  const std::string output =
+      GetOperandNameById(layer_normalization.output_operand_id);
+
+  const DataTypeLimits& data_type_limits = context_properties_.data_type_limits;
+  const OperandDescriptor& input_descriptor =
+      GetOperand(layer_normalization.input_operand_id).descriptor;
+  CHECK(data_type_limits.layer_normalization_input.Supports(input_descriptor));
+
+  std::string scale, bias;
+  if (layer_normalization.scale_operand_id) {
+    CHECK(data_type_limits.layer_normalization_input.Supports(
+        GetOperand(layer_normalization.scale_operand_id.value()).descriptor));
+    scale = GetOperandNameById(layer_normalization.scale_operand_id.value());
+  }
+  if (layer_normalization.bias_operand_id) {
+    CHECK(data_type_limits.layer_normalization_input.Supports(
+        GetOperand(layer_normalization.bias_operand_id.value()).descriptor));
+    bias = GetOperandNameById(layer_normalization.bias_operand_id.value());
+  }
+
+  std::vector<const char*> inputs = {input.c_str()};
+  std::array<const char*, 1> outputs = {output.c_str()};
+  const OperandDataType input_data_type = input_descriptor.data_type();
+  auto axes = layer_normalization.axes;
+  const std::vector<uint32_t>& input_shape = input_descriptor.shape();
+  // ONNX LayerNormalization doesn't support empty axes because it requires to
+  // set the first normalization dimension.
+  // https://onnx.ai/onnx/operators/onnx__LayerNormalization.html#attributes
+  // For WebNN layerNormalization, if axes is empty, no dimensions are reduced
+  // and the emulation can be simplified to `output = bias + (scale * 0).
+  // https://www.w3.org/TR/webnn/#dom-mllayernormalizationoptions-axes
+  if (axes.empty()) {
+    if (layer_normalization.bias_operand_id) {
+      const std::string zero =
+          CreateZeroInitializer(input_data_type, input_shape);
+      std::array<const char*, 2> add_inputs = {bias.c_str(), zero.c_str()};
+      return model_editor_.AddNode(kOpTypeAdd, node_name, add_inputs, outputs);
+    } else {
+      std::array<const char*, 2> sub_inputs = {input.c_str(), input.c_str()};
+      return model_editor_.AddNode(kOpTypeSub, node_name, sub_inputs, outputs);
+    }
+  }
+
+  const size_t axes_size = axes.size();
+  // Sort the indexes of the elements in the axes array based on their values
+  // and return the sorted index array for adding a transpose operation if
+  // needed. For example input shape is [2, 1, 4, 3], the shape of the scale and
+  // bias is [3, 1, 4] if axes is [3, 1, 2], the sorted axes would be [1, 2, 3],
+  // then the permutation would be (sorted indices array) [1, 2, 0].
+  std::optional<std::vector<uint32_t>> permutation;
+  if (!std::ranges::is_sorted(axes)) {
+    std::vector<uint32_t> sorted_indices(axes_size);
+    std::iota(sorted_indices.begin(), sorted_indices.end(), 0);
+    std::ranges::sort(sorted_indices, std::ranges::less(),
+                      [&axes](uint32_t index) { return axes[index]; });
+    permutation = std::move(sorted_indices);
+    std::ranges::sort(axes);
+  }
+
+  std::vector<uint32_t> scale_shape;
+  scale_shape.reserve(axes_size);
+  std::ranges::transform(
+      axes, std::back_inserter(scale_shape),
+      [&input_shape](uint32_t axis) { return input_shape[axis]; });
+  // Because ONNX LayerNormalization only accepts the first normalization
+  // dimension, it can only support WebNN layerNormalization whose axes are
+  // consecutive til the last dimension. Here we only check beginning and ending
+  // of the ascending sorted axes, because the blink validation code ensures
+  // axes not having duplicated values.
+  if (axes[axes_size - 1] == input_shape.size() - 1 &&
+      axes[0] == input_shape.size() - axes_size) {
+    if (layer_normalization.scale_operand_id) {
+      if (permutation.has_value()) {
+        scale = CreateTransposeNode(scale, permutation.value());
+      }
+    } else {
+      scale = CreateOneInitializer(input_data_type, scale_shape);
+    }
+    inputs.push_back(scale.c_str());
+
+    if (layer_normalization.bias_operand_id) {
+      if (permutation.has_value()) {
+        bias = CreateTransposeNode(bias, permutation.value());
+      }
+      inputs.push_back(bias.c_str());
+    }
+
+    std::array<ScopedOrtOpAttr, 2> attributes = {
+        model_editor_.CreateAttribute(kAttrAxis,
+                                      base::checked_cast<int64_t>(axes[0])),
+        model_editor_.CreateAttribute(kAttrEpsilon,
+                                      layer_normalization.epsilon)};
+
+    model_editor_.AddNode(kOpTypeLayerNormalization, node_name, inputs, outputs,
+                          attributes);
+  } else {
+    // Emulate layerNormalization by scale * ((input - mean) / sqrt(variance +
+    // epsilon)) + bias. Calculate mean as follows:
+    // reduceOptions = {axes, keepDimensions: true};
+    // mean = builder.reduceMean(input, reduceOptions).
+    const std::string reduce_mean_1_label = GenerateEmulatedOpLabel(
+        kOpTypeReduceMean, layer_normalization.label, "1");
+    const std::string reduce_mean_1_node_name =
+        GenerateNodeName(reduce_mean_1_label);
+    const std::string mean_output = GenerateOperandName();
+    std::string axes_name = CreateInt64InitializerForUint32Array(axes);
+    std::array<const char*, 2> reduce_mean_1_inputs = {input.c_str(),
+                                                       axes_name.c_str()};
+    std::array<const char*, 1> reduce_mean_1_outputs = {mean_output.c_str()};
+    std::array<ScopedOrtOpAttr, 2> reduce_mean_1_attributes = {
+        model_editor_.CreateAttribute(kAttrKeepDims, 1),
+        model_editor_.CreateAttribute(kAttrNoopWithEmptyAxes, 1)};
+    model_editor_.AddNode(kOpTypeReduceMean, reduce_mean_1_node_name,
+                          reduce_mean_1_inputs, reduce_mean_1_outputs,
+                          reduce_mean_1_attributes);
+
+    // Calculate variance as follows:
+    // powValue = builder.constant(input.dataType, 2);
+    // variance = builder.reduceMean(builder.pow(builder.sub(input, mean),
+    // powValue), reduceOptions);
+    const std::string sub_label =
+        GenerateEmulatedOpLabel(kOpTypeSub, layer_normalization.label);
+    const std::string sub_node_name = GenerateNodeName(sub_label);
+    const std::string sub_output = GenerateOperandName();
+
+    std::array<const char*, 2> sub_inputs = {input.c_str(),
+                                             mean_output.c_str()};
+    std::array<const char*, 1> sub_outputs = {sub_output.c_str()};
+    model_editor_.AddNode(kOpTypeSub, sub_node_name, sub_inputs, sub_outputs);
+
+    const std::string pow_label =
+        GenerateEmulatedOpLabel(kOpTypePow, layer_normalization.label);
+    std::string pow_node_name = GenerateNodeName(pow_label);
+    const std::string pow_output = GenerateOperandName();
+    std::string pow_value =
+        CreateScalarInitializer(input_data_type, MLNumber::FromFloat64(2.0f));
+    std::array<const char*, 2> pow_inputs = {sub_output.c_str(),
+                                             pow_value.c_str()};
+    std::array<const char*, 1> pow_outputs = {pow_output.c_str()};
+    model_editor_.AddNode(kOpTypePow, pow_node_name, pow_inputs, pow_outputs);
+
+    const std::string reduce_mean_2_label = GenerateEmulatedOpLabel(
+        kOpTypeReduceMean, layer_normalization.label, "2");
+    const std::string reduce_mean_2_node_name =
+        GenerateNodeName(reduce_mean_2_label);
+    const std::string variance_output = GenerateOperandName();
+    std::array<const char*, 2> reduce_mean_2_inputs = {pow_output.c_str(),
+                                                       axes_name.c_str()};
+    std::array<const char*, 1> reduce_mean_2_outputs = {
+        variance_output.c_str()};
+    std::array<ScopedOrtOpAttr, 2> reduce_mean_2_attributes = {
+        model_editor_.CreateAttribute(kAttrKeepDims, 1),
+        model_editor_.CreateAttribute(kAttrNoopWithEmptyAxes, 1)};
+    model_editor_.AddNode(kOpTypeReduceMean, reduce_mean_2_node_name,
+                          reduce_mean_2_inputs, reduce_mean_2_outputs,
+                          reduce_mean_2_attributes);
+
+    const std::string add_label =
+        GenerateEmulatedOpLabel(kOpTypeAdd, layer_normalization.label);
+    const std::string add_node_name = GenerateNodeName(add_label);
+    const std::string add_output = GenerateOperandName();
+    std::string epsilon_value = CreateScalarInitializer(
+        input_data_type, MLNumber::FromFloat64(layer_normalization.epsilon));
+    std::array<const char*, 2> add_inputs = {variance_output.c_str(),
+                                             epsilon_value.c_str()};
+    std::array<const char*, 1> add_outputs = {add_output.c_str()};
+    model_editor_.AddNode(kOpTypeAdd, add_node_name, add_inputs, add_outputs);
+
+    const std::string sqrt_label =
+        GenerateEmulatedOpLabel(kOpTypeSqrt, layer_normalization.label);
+    const std::string sqrt_node_name = GenerateNodeName(sqrt_label);
+    const std::string sqrt_output = GenerateOperandName();
+    std::array<const char*, 1> sqrt_inputs = {add_output.c_str()};
+    std::array<const char*, 1> sqrt_outputs = {sqrt_output.c_str()};
+    model_editor_.AddNode(kOpTypeSqrt, sqrt_node_name, sqrt_inputs,
+                          sqrt_outputs);
+
+    const std::string div_label =
+        GenerateEmulatedOpLabel(kOpTypeDiv, layer_normalization.label);
+    const std::string div_node_name = GenerateNodeName(div_label);
+    const std::string div_output = GenerateOperandName();
+    std::array<const char*, 2> div_inputs = {sub_output.c_str(),
+                                             sqrt_output.c_str()};
+    std::array<const char*, 1> div_outputs = {div_output.c_str()};
+    model_editor_.AddNode(kOpTypeDiv, div_node_name, div_inputs, div_outputs);
+
+    // Create compatible_shape for broadcasting scale and bias with intermediate
+    // results sach as `div_output` and `mul_output`. Initialize all dimensions
+    // to 1, then set normalization axes to match input dimensions for
+    // element-wise operations.
+    // Example: input_shape=[2,3,4,5], axes=[1,3] -> compatible_shape=[1,3,1,5].
+    std::vector<uint32_t> compatible_shape(input_shape.size(), 1);
+    for (auto axis : axes) {
+      compatible_shape[axis] = input_shape[axis];
+    }
+    if (layer_normalization.scale_operand_id) {
+      if (permutation.has_value()) {
+        scale = CreateTransposeNode(scale, permutation.value());
+      }
+      if (scale_shape.size() != input_shape.size()) {
+        scale = CreateReshapeNode(scale, compatible_shape);
+      }
+    } else {
+      scale = CreateOneInitializer(input_data_type, compatible_shape);
+    }
+
+    const std::string mul_label =
+        GenerateEmulatedOpLabel(kOpTypeMul, layer_normalization.label);
+    const std::string mul_node_name = GenerateNodeName(mul_label);
+    std::array<const char*, 2> mul_inputs = {scale.c_str(), div_output.c_str()};
+    if (layer_normalization.bias_operand_id) {
+      const std::string mul_output = GenerateOperandName();
+      std::array<const char*, 1> mul_outputs = {mul_output.c_str()};
+      model_editor_.AddNode(kOpTypeMul, mul_node_name, mul_inputs, mul_outputs);
+      if (permutation.has_value()) {
+        bias = CreateTransposeNode(bias, permutation.value());
+      }
+      if (scale_shape.size() != input_shape.size()) {
+        bias = CreateReshapeNode(bias, compatible_shape);
+      }
+
+      const std::string add_2_label =
+          GenerateEmulatedOpLabel(kOpTypeAdd, layer_normalization.label, "2");
+      const std::string add_2_node_name = GenerateNodeName(add_2_label);
+      std::array<const char*, 2> add_2_inputs = {mul_output.c_str(),
+                                                 bias.c_str()};
+      model_editor_.AddNode(kOpTypeAdd, add_2_node_name, add_2_inputs, outputs);
+    } else {
+      model_editor_.AddNode(kOpTypeMul, mul_node_name, mul_inputs, outputs);
+    }
+  }
+}
+
 void GraphBuilderOrt::AddLeakyReluOperation(
     const mojom::LeakyRelu& leaky_relu) {
   const std::string node_name = GenerateNodeName(leaky_relu.label);
@@ -1488,8 +2176,8 @@
       input_data_type, MLNumber::FromFloat64(linear.beta));
 
   // Step 1: Create 'Mul' node (alpha * x)
-  const std::string mul_node_label = base::JoinString(
-      {kInserted, kOpTypeMul, kToEmulate, linear.label}, kUnderscore);
+  const std::string mul_node_label =
+      GenerateEmulatedOpLabel(kOpTypeMul, linear.label);
   const std::string mul_node_name = GenerateNodeName(mul_node_label);
   const std::string input = GetOperandNameById(linear.input_operand_id);
   std::array<const char*, 2> mul_inputs = {input.c_str(), alpha.c_str()};
@@ -1498,8 +2186,8 @@
   model_editor_.AddNode(kOpTypeMul, mul_node_name, mul_inputs, mul_outputs);
 
   // Step 2: Create 'Add' node (mul_output + beta)
-  const std::string add_node_label = base::JoinString(
-      {kInserted, kOpTypeAdd, kToEmulate, linear.label}, kUnderscore);
+  const std::string add_node_label =
+      GenerateEmulatedOpLabel(kOpTypeAdd, linear.label);
   const std::string add_node_name = GenerateNodeName(add_node_label);
   std::array<const char*, 2> add_inputs = {mul_output.c_str(), beta.c_str()};
   const std::string output = GetOperandNameById(linear.output_operand_id);
@@ -1624,17 +2312,18 @@
   //
   // TODO(crbug.com/429272269): Remove the workaround for reduction operations
   // when ORT issue is fixed.
+  // https://github.com/onnx/onnx/issues/6103
   if (reduce.axes.empty()) {
     switch (reduce.kind) {
       case mojom::Reduce::Kind::kLogSum: {
-        const std::string node_name = GenerateNodeName(base::JoinString(
-            {kInserted, kOpTypeLog, kToEmulate, reduce.label}, kUnderscore));
+        const std::string node_name =
+            GenerateNodeName(GenerateEmulatedOpLabel(kOpTypeLog, reduce.label));
         model_editor_.AddNode(kOpTypeLog, node_name, inputs, outputs);
         return;
       }
       case mojom::Reduce::Kind::kSumSquare: {
-        const std::string node_name = GenerateNodeName(base::JoinString(
-            {kInserted, kOpTypePow, kToEmulate, reduce.label}, kUnderscore));
+        const std::string node_name =
+            GenerateNodeName(GenerateEmulatedOpLabel(kOpTypePow, reduce.label));
         const std::string pow = CreateScalarInitializer<int64_t>(2);
         inputs.push_back(pow.c_str());
         model_editor_.AddNode(kOpTypePow, node_name, inputs, outputs);
@@ -1642,8 +2331,8 @@
       }
       case mojom::Reduce::Kind::kL1:
       case mojom::Reduce::Kind::kL2: {
-        const std::string node_name = GenerateNodeName(base::JoinString(
-            {kInserted, kOpTypeAbs, kToEmulate, reduce.label}, kUnderscore));
+        const std::string node_name =
+            GenerateNodeName(GenerateEmulatedOpLabel(kOpTypeAbs, reduce.label));
         model_editor_.AddNode(kOpTypeAbs, node_name, inputs, outputs);
         return;
       }
@@ -1998,19 +2687,33 @@
 }
 
 void GraphBuilderOrt::AddTileOperation(const mojom::Tile& tile) {
-  const std::string node_name = GenerateNodeName(tile.label);
   const std::string input = GetOperandNameById(tile.input_operand_id);
   const std::string output = GetOperandNameById(tile.output_operand_id);
 
+  const OperandDescriptor& input_descriptor =
+      GetOperand(tile.input_operand_id).descriptor;
   CHECK(context_properties_.data_type_limits.tile_input.Supports(
-      GetOperand(tile.input_operand_id).descriptor));
+      input_descriptor));
+
+  std::vector<const char*> inputs = {input.c_str()};
+  std::array<const char*, 1> outputs = {output.c_str()};
+
+  // Emulate the tile operation with identity operation for unsupported scalar
+  // input.
+  // TODO(crbug.com/433414906): Remove the workaround for unsupported scalar
+  // input when the ORT tile operation issue is fixed.
+  // https://github.com/microsoft/onnxruntime/issues/11523
+  if (input_descriptor.Rank() == 0) {
+    const std::string node_name = GenerateNodeName(base::JoinString(
+        {kInserted, kOpTypeIdentity, kToEmulate, tile.label}, kUnderscore));
+    model_editor_.AddNode(kOpTypeIdentity, node_name, inputs, outputs);
+    return;
+  }
 
   const std::string repeats =
       CreateInt64InitializerForUint32Array(tile.repetitions);
-
-  std::array<const char*, 2> inputs = {input.data(), repeats.data()};
-  std::array<const char*, 1> outputs = {output.c_str()};
-
+  inputs.push_back(repeats.c_str());
+  const std::string node_name = GenerateNodeName(tile.label);
   model_editor_.AddNode(kOpTypeTile, node_name, inputs, outputs);
 }
 
@@ -2022,16 +2725,7 @@
   CHECK(context_properties_.data_type_limits.transpose_input.Supports(
       GetOperand(transpose.input_operand_id).descriptor));
 
-  std::array<const char*, 1> inputs = {input.c_str()};
-  std::array<const char*, 1> outputs = {output.c_str()};
-
-  std::vector<int64_t> perm_value(transpose.permutation.begin(),
-                                  transpose.permutation.end());
-  std::array<ScopedOrtOpAttr, 1> attributes = {
-      model_editor_.CreateAttribute(kAttrPerm, perm_value)};
-
-  model_editor_.AddNode(kOpTypeTranspose, node_name, inputs, outputs,
-                        attributes);
+  AddTransposeNode(node_name, input, output, transpose.permutation);
 }
 
 void GraphBuilderOrt::AddTriangularOperation(
@@ -2128,6 +2822,20 @@
         AddCumulativeSumOperation(*operation->get_cumulative_sum());
         break;
       }
+      case mojom::Operation::Tag::kDequantizeLinear: {
+        CHECK(data_type_limits.dequantize_linear_input.SupportsAll(
+            {GetOperand(operation->get_dequantize_linear()->input_operand_id)
+                 .descriptor,
+             GetOperand(
+                 operation->get_dequantize_linear()->zero_point_operand_id)
+                 .descriptor}));
+        CHECK(data_type_limits.dequantize_linear_scale.Supports(
+            GetOperand(operation->get_dequantize_linear()->scale_operand_id)
+                .descriptor));
+        RETURN_IF_ERROR(AddDequantizeOrQuantizeLinearOperation(
+            *operation->get_dequantize_linear(), kOpTypeDequantizeLinear));
+        break;
+      }
       case mojom::Operation::Tag::kElu: {
         AddEluOperation(*operation->get_elu());
         break;
@@ -2178,6 +2886,14 @@
         AddGemmOperation(*operation->get_gemm());
         break;
       }
+      case mojom::Operation::Tag::kGru: {
+        AddGruOperation(*operation->get_gru());
+        break;
+      }
+      case mojom::Operation::Tag::kGruCell: {
+        AddGruOperation(*operation->get_gru_cell());
+        break;
+      }
       case mojom::Operation::Tag::kHardSigmoid: {
         AddHardSigmoidOperation(*operation->get_hard_sigmoid());
         break;
@@ -2194,6 +2910,10 @@
             *operation->get_instance_normalization());
         break;
       }
+      case mojom::Operation::Tag::kLayerNormalization: {
+        AddLayerNormalizationOperation(*operation->get_layer_normalization());
+        break;
+      }
       case mojom::Operation::Tag::kLeakyRelu: {
         AddLeakyReluOperation(*operation->get_leaky_relu());
         break;
@@ -2218,6 +2938,19 @@
         AddPreluOperation(*operation->get_prelu());
         break;
       }
+      case mojom::Operation::Tag::kQuantizeLinear: {
+        CHECK(data_type_limits.quantize_linear_input.SupportsAll(
+            {GetOperand(operation->get_quantize_linear()->input_operand_id)
+                 .descriptor,
+             GetOperand(operation->get_quantize_linear()->scale_operand_id)
+                 .descriptor}));
+        CHECK(data_type_limits.quantize_linear_zero_point.Supports(
+            GetOperand(operation->get_quantize_linear()->zero_point_operand_id)
+                .descriptor));
+        RETURN_IF_ERROR(AddDequantizeOrQuantizeLinearOperation(
+            *operation->get_quantize_linear(), kOpTypeQuantizeLinear));
+        break;
+      }
       case mojom::Operation::Tag::kRelu: {
         CHECK(data_type_limits.relu_input.Supports(
             GetOperand(operation->get_relu()->input_operand_id).descriptor));
@@ -2302,13 +3035,8 @@
         AddWhereOperation(*operation->get_where());
         break;
       }
-      case mojom::Operation::Tag::kDequantizeLinear:
-      case mojom::Operation::Tag::kGru:
-      case mojom::Operation::Tag::kGruCell:
-      case mojom::Operation::Tag::kLayerNormalization:
       case mojom::Operation::Tag::kLstm:
       case mojom::Operation::Tag::kLstmCell:
-      case mojom::Operation::Tag::kQuantizeLinear:
         NOTREACHED() << "[WebNN] Unsupported operation.";
     }
   }
diff --git a/services/webnn/ort/graph_builder_ort.h b/services/webnn/ort/graph_builder_ort.h
index daf5070..77f72a480 100644
--- a/services/webnn/ort/graph_builder_ort.h
+++ b/services/webnn/ort/graph_builder_ort.h
@@ -95,6 +95,12 @@
   // `next_operation_id_`. ORT model doesn't allow duplicate names.
   std::string GenerateNodeName(std::string_view label);
 
+  // Generate a label for emulated operations by combining kInserted, op_type,
+  // optional additional_tag, kToEmulate, and the original operation label.
+  std::string GenerateEmulatedOpLabel(base::cstring_view op_type,
+                                      std::string_view original_label,
+                                      std::string_view additional_tag = "");
+
   // Create a new initializer for the graph with the given shape and data,
   // returning the name of the initializer.
   template <typename DataType>
@@ -126,7 +132,7 @@
   // an initializer of `shape` with all elements set to `value`. The data type
   // of the initializer is determined by the `data_type` parameter.
   std::string CreateInitializerForFloat(OperandDataType data_type,
-                                        base::span<const int64_t> shape,
+                                        base::span<const uint32_t> shape,
                                         float value);
 
   // A helper method wrapping the `CreateScalarInitializer` method above. It
@@ -138,11 +144,23 @@
 
   // A helper method creating an initializer with all elements set to 1.
   std::string CreateOneInitializer(OperandDataType data_type,
-                                   base::span<const int64_t> shape);
+                                   base::span<const uint32_t> shape);
 
   // A helper method creating an initializer with all elements set to 0.
   std::string CreateZeroInitializer(OperandDataType data_type,
-                                    base::span<const int64_t> shape);
+                                    base::span<const uint32_t> shape);
+
+  // A helper function used to transpose the weight or bias layout for the RNN
+  // operations (GRU, LSTM, etc.).
+  //
+  // Example:
+  //   To transpose gru weight or bias from "rzn" layout to "zrn" layout, pass
+  //   permutation as {1, 0, 2}.
+  //   To transpose lstm weight or bias from "ifgo" layout to "iofg" layout,
+  //   pass permutation as {0, 3, 1, 2}
+  std::string TransposeRnnWeightOrBiasLayout(
+      base::cstring_view weight_or_bias,
+      base::span<const uint32_t> permutation);
 
   void AddCastNode(base::cstring_view node_name,
                    base::cstring_view input,
@@ -179,6 +197,13 @@
                     base::span<const int64_t> ends_value,
                     base::span<const int64_t> steps_value);
 
+  void AddTransposeNode(base::cstring_view node_name,
+                        base::cstring_view input,
+                        base::cstring_view output,
+                        base::span<const uint32_t> perm_value);
+  std::string CreateTransposeNode(base::cstring_view input,
+                                  base::span<const uint32_t> perm_value);
+
   // Clamp the indices to the range [-dim_size, dim_size), the given data type
   // should be indices's data type.
   std::string ClampIndices(base::cstring_view indices,
@@ -207,6 +232,12 @@
   void AddConcatOperation(const mojom::Concat& concat);
   void AddConv2dOperation(const mojom::Conv2d& conv2d);
   void AddCumulativeSumOperation(const mojom::CumulativeSum& cumulative_sum);
+  template <typename T>
+    requires(std::is_same_v<T, mojom::DequantizeLinear> ||
+             std::is_same_v<T, mojom::QuantizeLinear>)
+  [[nodiscard]] base::expected<void, mojom::ErrorPtr>
+  AddDequantizeOrQuantizeLinearOperation(const T& operation,
+                                         base::cstring_view op_type);
   void AddEluOperation(const mojom::Elu& elu);
   void AddLogicalBinaryOperation(const mojom::ElementWiseBinary& logical_binary,
                                  base::cstring_view op_type);
@@ -219,9 +250,15 @@
   void AddExpandOperation(const mojom::Expand& expand);
   void AddGatherNDOperation(const mojom::GatherND& gather_nd);
   void AddGemmOperation(const mojom::Gemm& gemm);
+  template <typename GruType>
+    requires(std::is_same_v<GruType, mojom::Gru> ||
+             std::is_same_v<GruType, mojom::GruCell>)
+  void AddGruOperation(const GruType& gru);
   void AddHardSigmoidOperation(const mojom::HardSigmoid& hard_sigmoid);
   void AddInstanceNormalizationOperation(
       const mojom::InstanceNormalization& instance_normalization);
+  void AddLayerNormalizationOperation(
+      const mojom::LayerNormalization& layer_normalization);
   void AddLeakyReluOperation(const mojom::LeakyRelu& leaky_relu);
   void AddLinearOperation(const mojom::Linear& linear);
   void AddMatMulOperation(const mojom::Matmul& matmul);
diff --git a/services/webnn/ort/graph_impl_ort.cc b/services/webnn/ort/graph_impl_ort.cc
index 2d43c648..c413dff8 100644
--- a/services/webnn/ort/graph_impl_ort.cc
+++ b/services/webnn/ort/graph_impl_ort.cc
@@ -97,10 +97,11 @@
     }
 
     const OrtApi* ort_api = PlatformFunctions::GetInstance()->ort_api();
-    CHECK_STATUS(ort_api->Run(session_.get(), nullptr, input_names.data(),
-                              input_tensors.data(), input_names.size(),
-                              output_names.data(), output_names.size(),
-                              output_tensors.data()));
+    // TODO(crbug.com/433543131): Handle the inference error of MLGraph.
+    CALL_ORT_FUNC(ort_api->Run(session_.get(), nullptr, input_names.data(),
+                               input_tensors.data(), input_names.size(),
+                               output_names.data(), output_names.size(),
+                               output_tensors.data()));
   }
 
  private:
diff --git a/services/webnn/ort/ort_session_options.cc b/services/webnn/ort/ort_session_options.cc
index 670e1662..fb8788e 100644
--- a/services/webnn/ort/ort_session_options.cc
+++ b/services/webnn/ort/ort_session_options.cc
@@ -17,8 +17,8 @@
 namespace webnn::ort {
 
 // static
-base::expected<scoped_refptr<SessionOptions>, mojom::ErrorPtr>
-SessionOptions::Create(mojom::Device device_type) {
+scoped_refptr<SessionOptions> SessionOptions::Create(
+    mojom::Device device_type) {
   ScopedTrace scoped_trace("SessionOptions::Create");
 
   scoped_trace.AddStep("Create session options");
diff --git a/services/webnn/ort/ort_session_options.h b/services/webnn/ort/ort_session_options.h
index b759a58..f7df767 100644
--- a/services/webnn/ort/ort_session_options.h
+++ b/services/webnn/ort/ort_session_options.h
@@ -6,7 +6,6 @@
 #define SERVICES_WEBNN_ORT_ORT_SESSION_OPTIONS_H_
 
 #include "base/memory/scoped_refptr.h"
-#include "base/types/expected.h"
 #include "base/types/pass_key.h"
 #include "services/webnn/ort/scoped_ort_types.h"
 #include "services/webnn/public/mojom/webnn_device.mojom.h"
@@ -19,11 +18,8 @@
 // sessions on background threads.
 class SessionOptions final : public base::RefCountedThreadSafe<SessionOptions> {
  public:
-  // The `device_type` would be used to configure ONNX Runtime EP. Currently,
-  // only CPU is supported by the default CPU EP.
-  // It may fail when appending a particular EP to the session options.
-  static base::expected<scoped_refptr<SessionOptions>, mojom::ErrorPtr> Create(
-      mojom::Device device_type);
+  // The `device_type` would be used to configure ONNX Runtime EP.
+  static scoped_refptr<SessionOptions> Create(mojom::Device device_type);
 
   SessionOptions(base::PassKey<SessionOptions>,
                  ScopedOrtSessionOptions session_options);
diff --git a/services/webnn/public/cpp/graph_validation_utils.cc b/services/webnn/public/cpp/graph_validation_utils.cc
index a1e4635..dcec1866 100644
--- a/services/webnn/public/cpp/graph_validation_utils.cc
+++ b/services/webnn/public/cpp/graph_validation_utils.cc
@@ -947,14 +947,14 @@
     base::span<const uint32_t> zero_point_shape,
     std::string_view label) {
   // Check whether `scale_shape` is a subsample of `input_shape`.
-  if (scale_shape.size() > input_shape.size()) {
+  if (scale_shape.size() != input_shape.size()) {
     return base::unexpected(ErrorWithLabel(
-        label, "The rank of scale is larger than the rank of input."));
+        label, "The rank of scale is not equal to the rank of input."));
   }
 
   for (size_t i = 0; i < scale_shape.size(); ++i) {
-    auto scale_dim = scale_shape[scale_shape.size() - i - 1];
-    auto input_dim = input_shape[input_shape.size() - i - 1];
+    auto scale_dim = scale_shape[i];
+    auto input_dim = input_shape[i];
     // The block_size should be an integer where block_size = dim_input /
     // dim_scale along the axis.
     if (input_dim % scale_dim != 0) {
diff --git a/services/webnn/webnn_context_provider_impl.cc b/services/webnn/webnn_context_provider_impl.cc
index 0793797..92b49c0 100644
--- a/services/webnn/webnn_context_provider_impl.cc
+++ b/services/webnn/webnn_context_provider_impl.cc
@@ -19,9 +19,13 @@
 #include "services/webnn/webnn_context_impl.h"
 
 #if BUILDFLAG(IS_WIN)
+#include <string>
+
 #include "base/types/expected_macros.h"
 #include "services/webnn/dml/context_provider_dml.h"
+#include "services/webnn/ort/context_impl_ort.h"
 #include "services/webnn/ort/context_provider_ort.h"
+#include "services/webnn/ort/environment.h"
 #include "services/webnn/ort/ort_session_options.h"
 #endif
 
@@ -208,24 +212,22 @@
   RecordDeviceType(options->device);
 
 #if BUILDFLAG(IS_WIN)
-  base::expected<std::unique_ptr<WebNNContextImpl>, mojom::ErrorPtr>
-      context_creation_results;
-
   if (ort::ShouldCreateOrtContext(*options)) {
-    context_creation_results = ort::CreateContextFromOptions(
-        std::move(options), gpu_info_, std::move(receiver), this);
-    if (!context_creation_results.has_value()) {
-      std::move(callback).Run(mojom::CreateContextResult::NewError(
-          std::move(context_creation_results.error())));
-      return;
+    base::expected<scoped_refptr<ort::Environment>, std::string>
+        env_creation_results = ort::Environment::Create(gpu_info_);
+    if (!env_creation_results.has_value()) {
+      LOG(ERROR) << "[WebNN] Failed to create ONNX Runtime context: "
+                 << env_creation_results.error();
+    } else {
+      context_impl = std::make_unique<ort::ContextImplOrt>(
+          std::move(receiver), this, std::move(options),
+          std::move(env_creation_results.value()));
     }
-    context_impl = std::move(context_creation_results.value());
-  }
-
-  if (!context_impl && dml::ShouldCreateDmlContext(*options)) {
-    context_creation_results = dml::CreateContextFromOptions(
-        std::move(options), gpu_feature_info_, gpu_info_,
-        shared_context_state_.get(), std::move(receiver), this);
+  } else if (dml::ShouldCreateDmlContext(*options)) {
+    base::expected<std::unique_ptr<WebNNContextImpl>, mojom::ErrorPtr>
+        context_creation_results = dml::CreateContextFromOptions(
+            std::move(options), gpu_feature_info_, gpu_info_,
+            shared_context_state_.get(), std::move(receiver), this);
     if (!context_creation_results.has_value()) {
       std::move(callback).Run(mojom::CreateContextResult::NewError(
           std::move(context_creation_results.error())));
@@ -256,11 +258,11 @@
 #endif  // BUILDFLAG(WEBNN_USE_TFLITE)
 
   if (!context_impl) {
-    // TODO(crbug.com/40206287): Supporting WebNN Service on the platform.
+    // TODO(crbug.com/40206287): Supporting WebNN on the platform.
     std::move(callback).Run(ToError<mojom::CreateContextResult>(
         mojom::Error::Code::kNotSupportedError,
-        "WebNN Service is not supported on this platform."));
-    LOG(ERROR) << "[WebNN] Service is not supported on this platform.";
+        "WebNN is not supported on this platform."));
+    LOG(ERROR) << "WebNN is not supported on this platform.";
     return;
   }
 
diff --git a/services/webnn/webnn_context_provider_impl_unittest.cc b/services/webnn/webnn_context_provider_impl_unittest.cc
index 1b5bfd10..30c6ae1 100644
--- a/services/webnn/webnn_context_provider_impl_unittest.cc
+++ b/services/webnn/webnn_context_provider_impl_unittest.cc
@@ -73,7 +73,7 @@
   const mojom::ErrorPtr& create_context_error = result->get_error();
   EXPECT_EQ(create_context_error->code, mojom::Error::Code::kNotSupportedError);
   EXPECT_EQ(create_context_error->message,
-            "WebNN Service is not supported on this platform.");
+            "WebNN is not supported on this platform.");
 }
 
 #endif
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc
index 7f1b591..69e41038 100644
--- a/services/webnn/webnn_graph_impl_unittest.cc
+++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -1675,8 +1675,8 @@
     // Test dequantizeLinear operator with a broadcastable scale.
     DequantizeLinearTester{
         .input = {.type = OperandDataType::kInt8, .dimensions = {3, 2, 5}},
-        .scale = {.type = OperandDataType::kFloat32, .dimensions = {5}},
-        .zero_point = {.type = OperandDataType::kInt8, .dimensions = {5}},
+        .scale = {.type = OperandDataType::kFloat32, .dimensions = {1, 1, 5}},
+        .zero_point = {.type = OperandDataType::kInt8, .dimensions = {1, 1, 5}},
         .output = {.type = OperandDataType::kFloat32, .dimensions = {3, 2, 5}},
         .expected = true}
         .Test(*this);
@@ -1692,6 +1692,16 @@
         .Test(*this);
   }
   {
+    // Test the invalid graph whose scale rank is not equal to input rank.
+    DequantizeLinearTester{
+        .input = {.type = OperandDataType::kInt8, .dimensions = {3, 2, 5}},
+        .scale = {.type = OperandDataType::kFloat32, .dimensions = {5}},
+        .zero_point = {.type = OperandDataType::kInt8, .dimensions = {5}},
+        .output = {.type = OperandDataType::kFloat32, .dimensions = {3, 2, 5}},
+        .expected = false}
+        .Test(*this);
+  }
+  {
     // Test the invalid graph with an invalid scale.
     DequantizeLinearTester{
         .input = {.type = OperandDataType::kInt8, .dimensions = {3, 2, 5}},
@@ -5228,8 +5238,8 @@
     // Test quantizeLinear operator with a broadcastable scale.
     QuantizeLinearTester{
         .input = {.type = OperandDataType::kFloat32, .dimensions = {3, 2, 5}},
-        .scale = {.type = OperandDataType::kFloat32, .dimensions = {5}},
-        .zero_point = {.type = OperandDataType::kInt8, .dimensions = {5}},
+        .scale = {.type = OperandDataType::kFloat32, .dimensions = {1, 1, 5}},
+        .zero_point = {.type = OperandDataType::kInt8, .dimensions = {1, 1, 5}},
         .output = {.type = OperandDataType::kInt8, .dimensions = {3, 2, 5}},
         .expected = true}
         .Test(*this);
@@ -5245,6 +5255,16 @@
         .Test(*this);
   }
   {
+    // Test the invalid graph whose scale rank is not equal to input rank.
+    QuantizeLinearTester{
+        .input = {.type = OperandDataType::kFloat32, .dimensions = {3, 2, 5}},
+        .scale = {.type = OperandDataType::kFloat32, .dimensions = {5}},
+        .zero_point = {.type = OperandDataType::kInt8, .dimensions = {5}},
+        .output = {.type = OperandDataType::kInt8, .dimensions = {3, 2, 5}},
+        .expected = false}
+        .Test(*this);
+  }
+  {
     // Test the invalid graph with an invalid scale.
     QuantizeLinearTester{
         .input = {.type = OperandDataType::kFloat32, .dimensions = {3, 2, 5}},
diff --git a/storage/browser/blob/blob_builder_from_stream.cc b/storage/browser/blob/blob_builder_from_stream.cc
index dba93a5..50324c00 100644
--- a/storage/browser/blob/blob_builder_from_stream.cc
+++ b/storage/browser/blob/blob_builder_from_stream.cc
@@ -2,13 +2,9 @@
 // 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 "storage/browser/blob/blob_builder_from_stream.h"
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_macros.h"
@@ -320,12 +316,12 @@
                 uint64_t bytes_previously_written) override {
     if (item_->type() == BlobDataItem::Type::kBytesDescription)
       item_->AllocateBytes();
-    std::memcpy(
+    UNSAFE_TODO(std::memcpy(
         item_->mutable_bytes()
             .subspan(base::checked_cast<size_t>(bytes_previously_written),
                      data.size())
             .data(),
-        data.data(), data.size());
+        data.data(), data.size()));
     return true;
   }
 
diff --git a/storage/browser/blob/blob_data_builder.cc b/storage/browser/blob/blob_data_builder.cc
index 9eb4f95..63ab8f8 100644
--- a/storage/browser/blob/blob_data_builder.cc
+++ b/storage/browser/blob/blob_data_builder.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 "storage/browser/blob/blob_data_builder.h"
 
 #include <stddef.h>
@@ -15,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/files/file.h"
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
@@ -44,7 +40,7 @@
   if (!target.data())
     return false;
   DCHECK_EQ(target.size(), data.size());
-  std::memcpy(target.data(), data.data(), data.size());
+  UNSAFE_TODO(std::memcpy(target.data(), data.data(), data.size()));
   return true;
 }
 
diff --git a/storage/browser/blob/blob_flattener_unittest.cc b/storage/browser/blob/blob_flattener_unittest.cc
index f1cab2c..cf183c7c 100644
--- a/storage/browser/blob/blob_flattener_unittest.cc
+++ b/storage/browser/blob/blob_flattener_unittest.cc
@@ -2,15 +2,9 @@
 // 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 "storage/browser/blob/blob_storage_context.h"
-
 #include <memory>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -24,6 +18,7 @@
 #include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/blob_entry.h"
 #include "storage/browser/blob/blob_memory_controller.h"
+#include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/blob/blob_storage_registry.h"
 #include "storage/browser/blob/shareable_blob_data_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -78,7 +73,8 @@
   }
 
   scoped_refptr<BlobDataItem> CreateDataItem(const char* memory, size_t size) {
-    return BlobDataItem::CreateBytes(base::as_bytes(base::span(memory, size)));
+    return BlobDataItem::CreateBytes(
+        base::as_bytes(UNSAFE_TODO(base::span(memory, size))));
   }
 
   scoped_refptr<BlobDataItem> CreateFileItem(size_t offset, size_t size) {
diff --git a/storage/browser/blob/blob_memory_controller_unittest.cc b/storage/browser/blob/blob_memory_controller_unittest.cc
index 69ed53a..99b72ea8 100644
--- a/storage/browser/blob/blob_memory_controller_unittest.cc
+++ b/storage/browser/blob/blob_memory_controller_unittest.cc
@@ -2,16 +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 "storage/browser/blob/blob_memory_controller.h"
 
 #include <array>
 #include <optional>
 
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/functional/bind.h"
@@ -288,7 +284,7 @@
   AssertEnoughDiskSpace();
 
   char kData[kTestBlobStorageMaxBlobMemorySize];
-  std::memset(kData, 'e', kTestBlobStorageMaxBlobMemorySize);
+  UNSAFE_TODO(std::memset(kData, 'e', kTestBlobStorageMaxBlobMemorySize));
 
   // Add memory item that is the memory quota.
   BlobDataBuilder builder(kId);
@@ -374,7 +370,7 @@
   SetTestMemoryLimits(&controller);
 
   char kData[kTestBlobStorageMaxBlobMemorySize];
-  std::memset(kData, 'e', kTestBlobStorageMaxBlobMemorySize);
+  UNSAFE_TODO(std::memset(kData, 'e', kTestBlobStorageMaxBlobMemorySize));
 
   // Add memory item that is the memory quota.
   BlobDataBuilder builder(kId);
@@ -434,7 +430,7 @@
   SetTestMemoryLimits(&controller);
 
   char kData[kBlobSize];
-  std::memset(kData, 'e', kBlobSize);
+  UNSAFE_TODO(std::memset(kData, 'e', kBlobSize));
 
   // Add item that is the file quota.
   auto builder = std::make_unique<BlobDataBuilder>(kId);
@@ -491,7 +487,7 @@
   SetTestMemoryLimits(&controller);
 
   char kData[kBlobSize];
-  std::memset(kData, 'e', kBlobSize);
+  UNSAFE_TODO(std::memset(kData, 'e', kBlobSize));
 
   // Add memory item that is the memory quota.
   BlobDataBuilder builder(kId);
@@ -520,12 +516,12 @@
   const std::string kId1 = "id";
   const size_t kSize1 = kTestBlobStorageMaxFileSizeBytes;
   char kData1[kSize1];
-  std::memset(kData1, 'e', kSize1);
+  UNSAFE_TODO(std::memset(kData1, 'e', kSize1));
 
   const std::string kId2 = "id2";
   const size_t kSize2 = kTestBlobStorageMaxFileSizeBytes;
   char kData2[kSize2];
-  std::memset(kData2, 'f', kSize2);
+  UNSAFE_TODO(std::memset(kData2, 'f', kSize2));
 
   const std::string kId3 = "id3";
   const size_t kSize3 = kTestBlobStorageMaxBlobMemorySize - 1;
@@ -675,7 +671,7 @@
   const size_t kBlobsThatCanFit = kTotalBlobStorageSize / kDataSize;
   const size_t kNumFastBlobs = kTestBlobStorageMaxBlobMemorySize / kDataSize;
   char kData[10];
-  memset(kData, 'e', kDataSize);
+  UNSAFE_TODO(memset(kData, 'e', kDataSize));
 
   // Create all of our blobs.
   std::vector<scoped_refptr<ShareableBlobDataItem>> all_items;
@@ -802,7 +798,7 @@
   SetTestMemoryLimits(&controller);
 
   char kDataMemoryData[kFirstMemorySize];
-  std::memset(kDataMemoryData, 'e', kFirstMemorySize);
+  UNSAFE_TODO(std::memset(kDataMemoryData, 'e', kFirstMemorySize));
 
   // Add first memory item to fill up some memory quota.
   BlobDataBuilder builder(kFirstMemoryId);
diff --git a/storage/browser/blob/blob_reader.cc b/storage/browser/blob/blob_reader.cc
index d9effbe..a46d026 100644
--- a/storage/browser/blob/blob_reader.cc
+++ b/storage/browser/blob/blob_reader.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 "storage/browser/blob/blob_reader.h"
 
 #include <stddef.h>
@@ -17,6 +12,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/ptr_util.h"
@@ -556,9 +552,9 @@
   TRACE_EVENT1("Blob", "BlobReader::ReadBytesItem", "uuid", blob_data_->uuid());
   DCHECK_GE(read_buf_->BytesRemaining(), bytes_to_read);
 
-  memcpy(read_buf_->data(),
-         item.bytes().data() + item.offset() + current_item_offset_,
-         bytes_to_read);
+  UNSAFE_TODO(memcpy(read_buf_->data(),
+                     item.bytes().data() + item.offset() + current_item_offset_,
+                     bytes_to_read));
 
   AdvanceBytesRead(bytes_to_read);
 }
diff --git a/storage/browser/blob/blob_reader_unittest.cc b/storage/browser/blob/blob_reader_unittest.cc
index 23418f79..b9b43c7 100644
--- a/storage/browser/blob/blob_reader_unittest.cc
+++ b/storage/browser/blob/blob_reader_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 "storage/browser/blob/blob_reader.h"
 
 #include <stddef.h>
@@ -20,6 +15,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/heap_array.h"
 #include "base/containers/span.h"
 #include "base/files/file_path.h"
@@ -159,7 +155,7 @@
                net::CompletionOnceCallback done) {
     CHECK_GE(buf_length, 0);
     int length = std::min(buf_length, buffer_->BytesRemaining());
-    memcpy(buf->data(), buffer_->data(), length);
+    UNSAFE_TODO(memcpy(buf->data(), buffer_->data(), length));
     buffer_->DidConsume(length);
     if (done.is_null()) {
       return length;
@@ -329,7 +325,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize)));
 }
 
 TEST_F(BlobReaderTest, BasicFile) {
@@ -360,7 +356,8 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
+  UNSAFE_TODO(
+      EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())));
 }
 
 TEST_F(BlobReaderTest, BasicFileSystem) {
@@ -394,7 +391,8 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
+  UNSAFE_TODO(
+      EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())));
 }
 
 TEST_F(BlobReaderTest, BasicReadableDataHandle) {
@@ -422,7 +420,8 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size()));
+  UNSAFE_TODO(
+      EXPECT_EQ(0, memcmp(buffer->data(), "Test Blob Data", kData.size())));
 }
 
 TEST_F(BlobReaderTest, ReadableDataHandleWithSideData) {
@@ -476,7 +475,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kDataSize, static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "Hello!!!", kDataSize)));
 }
 
 TEST_F(BlobReaderTest, MemoryRange) {
@@ -505,7 +504,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "llo!", kReadLength));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "llo!", kReadLength)));
 }
 
 TEST_F(BlobReaderTest, BufferSmallerThanMemory) {
@@ -531,7 +530,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "Hell", kBufferSize));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "Hell", kBufferSize)));
 
   bytes_read = 0;
   EXPECT_EQ(BlobReader::Status::DONE,
@@ -540,7 +539,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "o!!!", kBufferSize));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "o!!!", kBufferSize)));
 }
 
 TEST_F(BlobReaderTest, SegmentedBufferAndMemory) {
@@ -578,7 +577,7 @@
     EXPECT_EQ(kBufferSize, static_cast<size_t>(bytes_read));
     EXPECT_EQ(0, async_bytes_read);
     for (size_t j = 0; j < kBufferSize; j++) {
-      EXPECT_EQ(current_value, buffer->data()[j]);
+      UNSAFE_TODO(EXPECT_EQ(current_value, buffer->data()[j]));
       current_value++;
     }
   }
@@ -619,7 +618,8 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
   EXPECT_EQ(0, bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
+  UNSAFE_TODO(
+      EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())));
 }
 
 TEST_F(BlobReaderTest, FileSystemAsync) {
@@ -659,7 +659,8 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kData.size(), static_cast<size_t>(async_bytes_read));
   EXPECT_EQ(0, bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size()));
+  UNSAFE_TODO(
+      EXPECT_EQ(0, memcmp(buffer->data(), "FileData!!!", kData.size())));
 }
 
 TEST_F(BlobReaderTest, ReadableDataHandleSingle) {
@@ -794,7 +795,7 @@
   EXPECT_EQ(0, async_bytes_read);
   EXPECT_EQ(kData.size(), static_cast<size_t>(bytes_read));
 
-  EXPECT_EQ(0, memcmp(buffer->data(), kData.data(), kData.size()));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), kData.data(), kData.size())));
 }
 
 TEST_F(BlobReaderTest, FileRange) {
@@ -839,7 +840,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kReadLength, static_cast<size_t>(async_bytes_read));
   EXPECT_EQ(0, bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "leD", kReadLength));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "leD", kReadLength)));
 }
 
 TEST_F(BlobReaderTest, ReadableDataHandleRange) {
@@ -867,7 +868,7 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(kReadLength, static_cast<size_t>(bytes_read));
   EXPECT_EQ(0, async_bytes_read);
-  EXPECT_EQ(0, memcmp(buffer->data(), "st ", kReadLength));
+  UNSAFE_TODO(EXPECT_EQ(0, memcmp(buffer->data(), "st ", kReadLength)));
 }
 
 TEST_F(BlobReaderTest, FileSomeAsyncSegmentedOffsetsUnknownSizes) {
@@ -900,13 +901,13 @@
     uint64_t offset = i % 3 == 0 ? 1 : 0;
     auto buf = base::HeapArray<char>::Uninit(kItemSize + offset);
     if (offset > 0) {
-      memset(buf.data(), 7, offset);
+      UNSAFE_TODO(memset(buf.data(), 7, offset));
     }
     for (size_t j = 0; j < kItemSize; j++) {
-      buf.data()[j + offset] = current_value++;
+      UNSAFE_TODO(buf.data()[j + offset]) = current_value++;
     }
     std::unique_ptr<FakeFileStreamReader> reader(new FakeFileStreamReader(
-        std::string(buf.data() + offset, kItemSize), buf.size()));
+        std::string(UNSAFE_TODO(buf.data() + offset), kItemSize), buf.size()));
     if (i % 4 != 0) {
       reader->SetAsyncRunner(
           base::SingleThreadTaskRunner::GetCurrentDefault().get());
@@ -939,7 +940,7 @@
     EXPECT_EQ(0, bytes_read);
     EXPECT_EQ(kBufferSize, static_cast<size_t>(async_bytes_read));
     for (size_t j = 0; j < kBufferSize; j++) {
-      EXPECT_EQ(current_value, buffer->data()[j]);
+      UNSAFE_TODO(EXPECT_EQ(current_value, buffer->data()[j]));
       current_value++;
     }
   }
@@ -994,8 +995,9 @@
   EXPECT_EQ(net::OK, reader_->net_error());
   EXPECT_EQ(0, bytes_read);
   EXPECT_EQ(kDataSize, static_cast<size_t>(async_bytes_read));
-  EXPECT_EQ(0, memcmp(buffer->data(), "Hello there. This is multi-content.",
-                      kDataSize));
+  UNSAFE_TODO(
+      EXPECT_EQ(0, memcmp(buffer->data(), "Hello there. This is multi-content.",
+                          kDataSize)));
 }
 
 TEST_F(BlobReaderTest, StateErrors) {
@@ -1204,7 +1206,8 @@
       BlobReader::Status::IO_PENDING,
       reader_->CalculateSize(base::BindOnce(&SetValue<int>, &size_result)));
   EXPECT_FALSE(reader_->IsInMemory());
-  future_data.Populate(base::as_bytes(base::span(kData.data(), kDataSize)), 0);
+  future_data.Populate(
+      base::as_bytes(UNSAFE_TODO(base::span(kData.data(), kDataSize))), 0);
   context_.NotifyTransportComplete(kUuid);
   base::RunLoop().RunUntilIdle();
   CheckSizeCalculatedAsynchronously(kDataSize, size_result);
diff --git a/storage/browser/blob/blob_storage_context_unittest.cc b/storage/browser/blob/blob_storage_context_unittest.cc
index 4dd487e..dc67185 100644
--- a/storage/browser/blob/blob_storage_context_unittest.cc
+++ b/storage/browser/blob/blob_storage_context_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 "storage/browser/blob/blob_storage_context.h"
 
 #include <stdint.h>
@@ -17,6 +12,7 @@
 #include <string>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -796,7 +792,8 @@
     std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
         std::move(builder),
         has_pending_memory
-            ? base::BindOnce(&SaveBlobStatusAndFiles, &statuses[0] + i, &files_)
+            ? base::BindOnce(&SaveBlobStatusAndFiles,
+                             UNSAFE_TODO(&statuses[0] + i), &files_)
             : BlobStorageContext::TransportAllowedCallback());
     handle->RunOnConstructionComplete(
         base::BindOnce(&IncrementNumber, &total_finished_blobs));
diff --git a/storage/browser/file_system/dump_file_system.cc b/storage/browser/file_system/dump_file_system.cc
index 58c870e..3dd5df3 100644
--- a/storage/browser/file_system/dump_file_system.cc
+++ b/storage/browser/file_system/dump_file_system.cc
@@ -26,11 +26,6 @@
 // children, and file_content_path is empty if the file is a directory.
 //
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -41,6 +36,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/compiler_specific.h"
 #include "base/containers/stack.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -115,7 +111,7 @@
     }
 
     // +1 for the leading extra slash.
-    const char* display_name = name.c_str() + 1;
+    const char* display_name = UNSAFE_TODO(name.c_str() + 1);
     const char* directory_suffix = info.is_directory() ? "/" : "";
     if (g_opt_long) {
       int64_t size;
@@ -125,14 +121,11 @@
         size = base::GetFileSize(origin_dir.Append(info.data_path)).value_or(0);
       }
       // TODO(hamaji): Modification time?
-      printf("%s%s %" PRId64 " %" PRId64 " %s\n",
-             display_name,
-             directory_suffix,
-             id,
-             size,
-             FilePathToString(info.data_path).c_str());
+      UNSAFE_TODO(printf("%s%s %" PRId64 " %" PRId64 " %s\n", display_name,
+                         directory_suffix, id, size,
+                         FilePathToString(info.data_path).c_str()));
     } else {
-      printf("%s%s\n", display_name, directory_suffix);
+      UNSAFE_TODO(printf("%s%s\n", display_name, directory_suffix));
     }
   }
 }
@@ -179,18 +172,18 @@
     if (argc < 2)
       ShowUsageAndExit(arg0);
 
-    if (std::string(argv[1]) == "-l") {
+    if (std::string(UNSAFE_TODO(argv[1])) == "-l") {
       g_opt_long = true;
       argc--;
-      argv++;
-    } else if (std::string(argv[1]) == "-t") {
+      UNSAFE_TODO(argv++);
+    } else if (std::string(UNSAFE_TODO(argv[1])) == "-t") {
       g_opt_fs_type = FILE_PATH_LITERAL("t");
       argc--;
-      argv++;
-    } else if (std::string(argv[1]) == "-s") {
+      UNSAFE_TODO(argv++);
+    } else if (std::string(UNSAFE_TODO(argv[1])) == "-s") {
       g_opt_fs_type = FILE_PATH_LITERAL("s");
       argc--;
-      argv++;
+      UNSAFE_TODO(argv++);
     } else {
       break;
     }
@@ -199,7 +192,8 @@
   if (argc < 2)
     ShowUsageAndExit(arg0);
 
-  const base::FilePath file_system_dir = storage::StringToFilePath(argv[1]);
+  const base::FilePath file_system_dir =
+      storage::StringToFilePath(UNSAFE_TODO(argv[1]));
   if (!base::DirectoryExists(file_system_dir)) {
     ShowMessageAndExit(storage::FilePathToString(file_system_dir) +
                        " is not a filesystem directory");
@@ -209,7 +203,7 @@
     storage::DumpFileSystem(file_system_dir);
   } else {
     for (int i = 2; i < argc; i++) {
-      storage::DumpOrigin(file_system_dir, argv[i]);
+      storage::DumpOrigin(file_system_dir, UNSAFE_TODO(argv[i]));
     }
   }
   return 0;
diff --git a/storage/browser/file_system/file_system_usage_cache.cc b/storage/browser/file_system/file_system_usage_cache.cc
index 475dcb6..9b91451 100644
--- a/storage/browser/file_system/file_system_usage_cache.cc
+++ b/storage/browser/file_system/file_system_usage_cache.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 "storage/browser/file_system/file_system_usage_cache.h"
 
 #include <stddef.h>
@@ -15,6 +10,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/files/file_util.h"
@@ -206,9 +202,12 @@
     return false;
   }
 
-  if (header[0] != kUsageFileHeader[0] || header[1] != kUsageFileHeader[1] ||
-      header[2] != kUsageFileHeader[2] || header[3] != kUsageFileHeader[3])
+  if (header[0] != kUsageFileHeader[0] ||
+      UNSAFE_TODO(header[1]) != kUsageFileHeader[1] ||
+      UNSAFE_TODO(header[2]) != kUsageFileHeader[2] ||
+      UNSAFE_TODO(header[3]) != kUsageFileHeader[3]) {
     return false;
+  }
 
   *dirty_out = dirty;
   *usage_out = usage;
@@ -267,7 +266,8 @@
   if (is_incognito_) {
     if (!base::Contains(incognito_usages_, file_path))
       return false;
-    memcpy(buffer.data(), incognito_usages_[file_path].data(), buffer.size());
+    UNSAFE_TODO(memcpy(buffer.data(), incognito_usages_[file_path].data(),
+                       buffer.size()));
     return true;
   }
   base::File* file = GetFile(file_path);
@@ -282,7 +282,8 @@
   if (is_incognito_) {
     if (!base::Contains(incognito_usages_, file_path))
       incognito_usages_[file_path] = std::vector<uint8_t>(buffer.size());
-    memcpy(incognito_usages_[file_path].data(), buffer.data(), buffer.size());
+    UNSAFE_TODO(memcpy(incognito_usages_[file_path].data(), buffer.data(),
+                       buffer.size()));
     return true;
   }
   base::File* file = GetFile(file_path);
diff --git a/storage/browser/test/fake_blob_data_handle.cc b/storage/browser/test/fake_blob_data_handle.cc
index d14a2a5..2302743 100644
--- a/storage/browser/test/fake_blob_data_handle.cc
+++ b/storage/browser/test/fake_blob_data_handle.cc
@@ -2,13 +2,9 @@
 // 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 "storage/browser/test/fake_blob_data_handle.h"
 
+#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/numerics/safe_conversions.h"
@@ -57,7 +53,7 @@
   }
 
   mojo_base::BigBuffer buffer(side_data_.size());
-  memcpy(buffer.data(), side_data_.data(), side_data_.size());
+  UNSAFE_TODO(memcpy(buffer.data(), side_data_.data(), side_data_.size()));
 
   std::move(callback).Run(side_data_.size(), std::move(buffer));
 }
diff --git a/storage/browser/test/mock_bytes_provider.cc b/storage/browser/test/mock_bytes_provider.cc
index 1792102f..dcb4cd9b 100644
--- a/storage/browser/test/mock_bytes_provider.cc
+++ b/storage/browser/test/mock_bytes_provider.cc
@@ -2,13 +2,9 @@
 // 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 "storage/browser/test/mock_bytes_provider.h"
 
+#include "base/compiler_specific.h"
 #include "base/threading/thread_restrictions.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -53,11 +49,12 @@
   if (file_request_count_)
     ++*file_request_count_;
   EXPECT_LE(source_offset + source_size, data_.size());
-  EXPECT_EQ(source_size,
-            static_cast<uint64_t>(file.Write(
-                file_offset,
-                reinterpret_cast<const char*>(data_.data() + source_offset),
-                source_size)));
+  UNSAFE_TODO(
+      EXPECT_EQ(source_size,
+                static_cast<uint64_t>(file.Write(
+                    file_offset,
+                    reinterpret_cast<const char*>(data_.data() + source_offset),
+                    source_size))));
   EXPECT_TRUE(file.Flush());
   std::move(callback).Run(file_modification_time_);
 }
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index c844481..a0edb74 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -207,6 +207,13 @@
               "{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
 
+bundle_data("media_unittests_filters_bundle_data") {
+  testonly = true
+  sources = [ "//testing/buildbot/filters/ios.media_unittests.filter" ]
+  outputs = [ "{{bundle_resources_dir}}/" +
+              "{{source_root_relative_dir}}/{{source_file_part}}" ]
+}
+
 source_set("content_browsertests_filters") {
   testonly = true
 
diff --git a/testing/buildbot/filters/android.emulator_16.content_browsertests.filter b/testing/buildbot/filters/android.emulator_16.content_browsertests.filter
index 91c7e66..8c23ab5 100644
--- a/testing/buildbot/filters/android.emulator_16.content_browsertests.filter
+++ b/testing/buildbot/filters/android.emulator_16.content_browsertests.filter
@@ -3,4 +3,7 @@
 -FormControlsBrowserTest.Button
 -FormControlsBrowserTest.Checkbox
 -FormControlsBrowserTest.MultiSelect
--FormControlsBrowserTest.Select
\ No newline at end of file
+-FormControlsBrowserTest.Select
+
+# crbug.com/382588633
+-Default/MediaTest.VideoBearWavPcm3kHz*
diff --git a/testing/buildbot/filters/ios.media_unittests.filter b/testing/buildbot/filters/ios.media_unittests.filter
index d900b499..dc4a16e 100644
--- a/testing/buildbot/filters/ios.media_unittests.filter
+++ b/testing/buildbot/filters/ios.media_unittests.filter
@@ -5,3 +5,6 @@
 -PaintCanvasVideoRendererWithGLTest.PaintI420
 -PaintCanvasVideoRendererWithGLTest.PaintI420NotSubset
 -PaintCanvasVideoRendererWithGLTest.PaintNV12
+
+-GpuMemoryBufferVideoFramePoolTest.CreateOne10BppHardwareFrameWithOddSize
+-GpuMemoryBufferVideoFramePoolTest.CreateOneHardwareP010FrameWithOddSize
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c67051f..211f9d5 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2057,21 +2057,6 @@
             ]
         }
     ],
-    "AutofillEnableCardBenefitsForAmericanExpress": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "AutofillEnableCardBenefitsForAmericanExpress"
-                    ]
-                }
-            ]
-        }
-    ],
     "AutofillEnableCardBenefitsForBmo": [
         {
             "platforms": [
@@ -2651,6 +2636,28 @@
             ]
         }
     ],
+    "AutofillRelaxAddressImport": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillEnableImportWhenMultiplePhoneNumbers",
+                        "AutofillRelaxAddressImport"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillRequireCvcForPossibleCardUpdate": [
         {
             "platforms": [
@@ -6308,23 +6315,6 @@
             ]
         }
     ],
-    "ComposeV3Migration": [
-        {
-            "platforms": [
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ComposeV3Migration"
-                    ]
-                }
-            ]
-        }
-    ],
     "CompositeBackgroundColorAnimation": [
         {
             "platforms": [
@@ -7180,7 +7170,7 @@
             ]
         }
     ],
-    "CrOSLocalImageSearchIca": [
+    "CrOSLocalImageSearchOcr": [
         {
             "platforms": [
                 "chromeos"
@@ -7189,8 +7179,7 @@
                 {
                     "name": "Enabled",
                     "enable_features": [
-                        "LauncherImageSearch",
-                        "LauncherImageSearchIca"
+                        "LauncherImageSearchOcr"
                     ]
                 }
             ]
@@ -9612,6 +9601,24 @@
             ]
         }
     ],
+    "EnterpriseIframeDlpRulesSupport": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "EnterpriseIframeDlpRulesSupport"
+                    ]
+                }
+            ]
+        }
+    ],
     "EsbAsASyncedSetting": [
         {
             "platforms": [
@@ -12928,28 +12935,13 @@
                     "name": "Enabled",
                     "enable_features": [
                         "EnableReaderMode",
+                        "EnableReaderModeDefaultBrowserPromo",
                         "EnableReaderModePageEligibilityForToolsMenu"
                     ]
                 }
             ]
         }
     ],
-    "IOSReaderModeMetrics": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "EnableReaderModeDistiller",
-                        "EnableReaderModeDistillerHeuristic"
-                    ]
-                }
-            ]
-        }
-    ],
     "IOSSaveToPhotosImprovements": [
         {
             "platforms": [
@@ -15240,25 +15232,6 @@
             ]
         }
     ],
-    "NavBarColorAnimationEnabled": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "params": {
-                        "disable_bottom_chin_color_animation": "false",
-                        "disable_edge_to_edge_layout_color_animation": "false"
-                    },
-                    "enable_features": [
-                        "NavBarColorAnimation"
-                    ]
-                }
-            ]
-        }
-    ],
     "NavigationThrottleRegistryAttributeCache": [
         {
             "platforms": [
@@ -15538,6 +15511,25 @@
             ]
         }
     ],
+    "NoLateBeginFrames": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NoLateBeginFrames"
+                    ]
+                }
+            ]
+        }
+    ],
     "NoPasswordSuggestionFiltering": [
         {
             "platforms": [
@@ -16165,7 +16157,8 @@
     "OmniboxMobileParityUpdateV2": [
         {
             "platforms": [
-                "android"
+                "android",
+                "ios"
             ],
             "experiments": [
                 {
@@ -19979,7 +19972,8 @@
                         "AvoidUnnecessaryGetMinimizeButtonOffset",
                         "AvoidUnnecessaryShouldRenderRichAnimation",
                         "ReducePPMs",
-                        "ScreenWinDisplayLookupByHMONITOR"
+                        "ScreenWinDisplayLookupByHMONITOR",
+                        "UpdateDirectManipulationHelperOnParentChange"
                     ]
                 }
             ]
@@ -22820,30 +22814,13 @@
                 {
                     "name": "Enabled",
                     "enable_features": [
+                        "DataSharing",
                         "DataSharingJoinOnly"
                     ]
                 }
             ]
         }
     ],
-    "SharedTabGroupsTeamfoodIPhone": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "form_factors": [
-                "phone"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DataSharing"
-                    ]
-                }
-            ]
-        }
-    ],
     "SharedWorkerBlobURLFix": [
         {
             "platforms": [
@@ -22990,6 +22967,32 @@
             ]
         }
     ],
+    "SideBySideDogfood": [
+        {
+            "platforms": [
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "SideBySide_Dogfood",
+                    "params": {
+                        "drop_target_max_width": "360",
+                        "drop_target_min_width": "88",
+                        "drop_target_show_delay": "700ms",
+                        "drop_target_width_percentage": "20",
+                        "mini_toolbar_active_config": "hide"
+                    },
+                    "enable_features": [
+                        "SideBySide",
+                        "SideBySideLinkMenuNewBadge",
+                        "SideBySideSessionRestore"
+                    ]
+                }
+            ]
+        }
+    ],
     "SidePanelCompanionDesktopM116Plus": [
         {
             "platforms": [
@@ -23248,16 +23251,16 @@
             ]
         }
     ],
-    "SkipIsolatedSplitPreload": [
+    "SkiaGraphitePrecompilation": [
         {
             "platforms": [
-                "android"
+                "mac"
             ],
             "experiments": [
                 {
                     "name": "Enabled",
                     "enable_features": [
-                        "SkipIsolatedSplitPreload"
+                        "SkiaGraphitePrecompilation"
                     ]
                 }
             ]
diff --git a/third_party/androidx/BUILD.gn b/third_party/androidx/BUILD.gn
index 48b18ed..8f50d04 100644
--- a/third_party/androidx/BUILD.gn
+++ b/third_party/androidx/BUILD.gn
@@ -227,7 +227,7 @@
       ":androidx_test_rules_java",
       ":androidx_test_runner_java",
       ":androidx_tracing_tracing_ktx_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -251,7 +251,7 @@
       ":androidx_tracing_tracing_perfetto_java",
       "//third_party/android_deps:com_squareup_wire_wire_runtime_java",
       "//third_party/android_deps:org_jspecify_jspecify_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -270,7 +270,7 @@
       ":androidx_test_rules_java",
       ":androidx_test_runner_java",
       ":androidx_test_uiautomator_uiautomator_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -525,7 +525,7 @@
       ":androidx_annotation_annotation_java",
       ":androidx_core_core_animation_java",
       ":androidx_core_core_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
     ]
   }
 
@@ -622,6 +622,11 @@
   }
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  androidx_java_group("androidx_datastore_datastore_preferences_java") {
+    deps = [ ":androidx_datastore_datastore_preferences_android_java" ]
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt("androidx_documentfile_documentfile_java") {
     aar_path = "../androidx/cipd/libs/androidx_documentfile_documentfile/documentfile-1.1.0.aar"
     info_path = "../androidx/committed/libs/androidx_documentfile_documentfile/androidx_documentfile_documentfile.info"
@@ -1103,13 +1108,13 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt("androidx_pdf_pdf_viewer_java") {
-    aar_path = "../androidx/cipd/libs/androidx_pdf_pdf_viewer/pdf-viewer-1.0.0-SNAPSHOT.aar"
-    info_path = "../androidx/committed/libs/androidx_pdf_pdf_viewer/androidx_pdf_pdf_viewer.info"
+    aar_path = "cipd/libs/androidx_pdf_pdf_viewer/pdf-viewer-1.0.0-alpha06.aar"
+    info_path =
+        "committed/libs/androidx_pdf_pdf_viewer/androidx_pdf_pdf_viewer.info"
     enable_bytecode_checks = false
     deps = [
       ":androidx_annotation_annotation_java",
       ":androidx_core_core_java",
-      ":androidx_customview_customview_java",
       ":androidx_exifinterface_exifinterface_java",
       "//third_party/android_deps:com_google_errorprone_error_prone_annotations_java",
       "//third_party/android_deps:material_design_java",
@@ -1121,8 +1126,8 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt("androidx_pdf_pdf_viewer_fragment_java") {
-    aar_path = "../androidx/cipd/libs/androidx_pdf_pdf_viewer_fragment/pdf-viewer-fragment-1.0.0-SNAPSHOT.aar"
-    info_path = "../androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/androidx_pdf_pdf_viewer_fragment.info"
+    aar_path = "cipd/libs/androidx_pdf_pdf_viewer_fragment/pdf-viewer-fragment-1.0.0-alpha06.aar"
+    info_path = "committed/libs/androidx_pdf_pdf_viewer_fragment/androidx_pdf_pdf_viewer_fragment.info"
     enable_bytecode_checks = false
     deps = [
       ":androidx_core_core_java",
@@ -1338,7 +1343,7 @@
       "//third_party/android_deps:javax_inject_javax_inject_java",
       "//third_party/hamcrest:hamcrest_core_java",
       "//third_party/hamcrest:hamcrest_library_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -1385,7 +1390,7 @@
       ":androidx_test_core_java",
       ":androidx_test_monitor_java",
       ":androidx_test_services_storage_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -1413,7 +1418,7 @@
     deps = [
       ":androidx_annotation_annotation_java",
       ":androidx_test_runner_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
     ]
   }
 
@@ -1429,7 +1434,7 @@
       ":androidx_test_monitor_java",
       ":androidx_test_services_storage_java",
       ":androidx_tracing_tracing_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
     ]
   }
 
@@ -1456,7 +1461,7 @@
       ":androidx_test_core_java",
       ":androidx_tracing_tracing_java",
       "//third_party/android_deps:org_jspecify_jspecify_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
     ]
   }
 
@@ -2199,7 +2204,7 @@
       ":androidx_test_monitor_java",
       "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
       "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_test_java",
-      "//third_party/junit:junit",
+      "//third_party/junit",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -2402,6 +2407,17 @@
   }
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  androidx_java_group("androidx_datastore_datastore_java") {
+    # To remove visibility constraint, add this dependency to
+    # //third_party/androidx/build.gradle.
+    visibility = [
+      ":*",
+      "//third_party/android_deps:*",
+    ]
+    deps = [ ":androidx_datastore_datastore_android_java" ]
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt(
       "androidx_datastore_datastore_core_android_java") {
     aar_path = "../androidx/cipd/libs/androidx_datastore_datastore_core_android/datastore-core-android-1.2.0-SNAPSHOT.aar"
@@ -2455,6 +2471,96 @@
   }
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  androidx_android_aar_prebuilt(
+      "androidx_datastore_datastore_preferences_android_java") {
+    aar_path = "../androidx/cipd/libs/androidx_datastore_datastore_preferences_android/datastore-preferences-android-1.2.0-SNAPSHOT.aar"
+    info_path = "../androidx/committed/libs/androidx_datastore_datastore_preferences_android/androidx_datastore_datastore_preferences_android.info"
+    enable_bytecode_checks = false
+
+    # To remove visibility constraint, add this dependency to
+    # //third_party/androidx/build.gradle.
+    visibility = [
+      ":*",
+      "//third_party/android_deps:*",
+    ]
+    deps = [
+      ":androidx_datastore_datastore_java",
+      ":androidx_datastore_datastore_preferences_core_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.
+  androidx_java_group("androidx_datastore_datastore_preferences_core_java") {
+    # To remove visibility constraint, add this dependency to
+    # //third_party/androidx/build.gradle.
+    visibility = [
+      ":*",
+      "//third_party/android_deps:*",
+    ]
+    deps = [ ":androidx_datastore_datastore_preferences_core_android_java" ]
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  androidx_android_aar_prebuilt(
+      "androidx_datastore_datastore_preferences_core_android_java") {
+    aar_path = "../androidx/cipd/libs/androidx_datastore_datastore_preferences_core_android/datastore-preferences-core-android-1.2.0-SNAPSHOT.aar"
+    info_path = "../androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/androidx_datastore_datastore_preferences_core_android.info"
+    enable_bytecode_checks = false
+
+    # To remove visibility constraint, add this dependency to
+    # //third_party/androidx/build.gradle.
+    visibility = [
+      ":*",
+      "//third_party/android_deps:*",
+    ]
+    deps = [
+      ":androidx_datastore_datastore_core_java",
+      ":androidx_datastore_datastore_core_okio_java",
+      ":androidx_datastore_datastore_preferences_proto_java",
+      "//third_party/android_deps:com_squareup_okio_okio_java",
+      "//third_party/kotlin_stdlib:kotlin_stdlib_java",
+    ]
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  androidx_java_prebuilt(
+      "androidx_datastore_datastore_preferences_external_protobuf_java") {
+    jar_path = "../androidx/cipd/libs/androidx_datastore_datastore_preferences_external_protobuf/datastore-preferences-external-protobuf-1.2.0-SNAPSHOT.jar"
+    output_name = "androidx_datastore_datastore_preferences_external_protobuf"
+    supports_android = true
+    requires_android = true
+    enable_bytecode_checks = false
+
+    # To remove visibility constraint, add this dependency to
+    # //third_party/androidx/build.gradle.
+    visibility = [
+      ":*",
+      "//third_party/android_deps:*",
+    ]
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+  androidx_java_prebuilt(
+      "androidx_datastore_datastore_preferences_proto_java") {
+    jar_path = "../androidx/cipd/libs/androidx_datastore_datastore_preferences_proto/datastore-preferences-proto-1.2.0-SNAPSHOT.jar"
+    output_name = "androidx_datastore_datastore_preferences_proto"
+    supports_android = true
+    requires_android = true
+    enable_bytecode_checks = false
+
+    # To remove visibility constraint, add this dependency to
+    # //third_party/androidx/build.gradle.
+    visibility = [
+      ":*",
+      "//third_party/android_deps:*",
+    ]
+    deps =
+        [ ":androidx_datastore_datastore_preferences_external_protobuf_java" ]
+  }
+
+  # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt("androidx_emoji2_emoji2_java") {
     aar_path =
         "../androidx/cipd/libs/androidx_emoji2_emoji2/emoji2-1.6.0-SNAPSHOT.aar"
@@ -3105,6 +3211,7 @@
       ":androidx_compose_runtime_runtime_java",
       ":androidx_compose_ui_ui_java",
       ":androidx_navigationevent_navigationevent_java",
+      "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -3198,8 +3305,8 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt("androidx_pdf_pdf_document_service_java") {
-    aar_path = "../androidx/cipd/libs/androidx_pdf_pdf_document_service/pdf-document-service-1.0.0-SNAPSHOT.aar"
-    info_path = "../androidx/committed/libs/androidx_pdf_pdf_document_service/androidx_pdf_pdf_document_service.info"
+    aar_path = "cipd/libs/androidx_pdf_pdf_document_service/pdf-document-service-1.0.0-alpha06.aar"
+    info_path = "committed/libs/androidx_pdf_pdf_document_service/androidx_pdf_pdf_document_service.info"
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
diff --git a/third_party/androidx/additional_readme_paths.json b/third_party/androidx/additional_readme_paths.json
index 018483d..2b3a1b0 100644
--- a/third_party/androidx/additional_readme_paths.json
+++ b/third_party/androidx/additional_readme_paths.json
@@ -63,6 +63,10 @@
     "committed/libs/androidx_datastore_datastore_android",
     "committed/libs/androidx_datastore_datastore_core_android",
     "committed/libs/androidx_datastore_datastore_core_okio_jvm",
+    "committed/libs/androidx_datastore_datastore_preferences_android",
+    "committed/libs/androidx_datastore_datastore_preferences_core_android",
+    "committed/libs/androidx_datastore_datastore_preferences_external_protobuf",
+    "committed/libs/androidx_datastore_datastore_preferences_proto",
     "committed/libs/androidx_documentfile_documentfile",
     "committed/libs/androidx_drawerlayout_drawerlayout",
     "committed/libs/androidx_dynamicanimation_dynamicanimation",
diff --git a/third_party/androidx/bill_of_materials.json b/third_party/androidx/bill_of_materials.json
index 301fb187..78f48fe 100644
--- a/third_party/androidx/bill_of_materials.json
+++ b/third_party/androidx/bill_of_materials.json
@@ -340,6 +340,11 @@
         "version": "1.2.0-SNAPSHOT"
     },
     {
+        "name": "constraintlayout-solver",
+        "group": "androidx.constraintlayout",
+        "version": "2.0.1"
+    },
+    {
         "name": "coordinatorlayout",
         "group": "androidx.coordinatorlayout",
         "version": "1.3.0"
@@ -405,6 +410,11 @@
         "version": "1.1.0"
     },
     {
+        "name": "datastore",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
         "name": "datastore-android",
         "group": "androidx.datastore",
         "version": "1.2.0-SNAPSHOT"
@@ -430,6 +440,36 @@
         "version": "1.2.0-SNAPSHOT"
     },
     {
+        "name": "datastore-preferences",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
+        "name": "datastore-preferences-android",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
+        "name": "datastore-preferences-core",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
+        "name": "datastore-preferences-core-android",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
+        "name": "datastore-preferences-external-protobuf",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
+        "name": "datastore-preferences-proto",
+        "group": "androidx.datastore",
+        "version": "1.2.0-SNAPSHOT"
+    },
+    {
         "name": "documentfile",
         "group": "androidx.documentfile",
         "version": "1.1.0"
@@ -822,17 +862,17 @@
     {
         "name": "pdf-document-service",
         "group": "androidx.pdf",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "1.0.0-alpha06"
     },
     {
         "name": "pdf-viewer",
         "group": "androidx.pdf",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "1.0.0-alpha06"
     },
     {
         "name": "pdf-viewer-fragment",
         "group": "androidx.pdf",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "1.0.0-alpha06"
     },
     {
         "name": "preference",
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index 92df7cb5..524ca06 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -83,6 +83,7 @@
 versionCache['androidx.concurrent:concurrent-futures-ktx'] = '1.3.0'
 versionCache['androidx.constraintlayout:constraintlayout'] = '2.3.0-SNAPSHOT'
 versionCache['androidx.constraintlayout:constraintlayout-core'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.constraintlayout:constraintlayout-solver'] = '2.0.1'
 versionCache['androidx.coordinatorlayout:coordinatorlayout'] = '1.3.0'
 versionCache['androidx.core:core'] = '1.17.0-SNAPSHOT'
 versionCache['androidx.core:core-animation'] = '1.0.0'
@@ -96,11 +97,18 @@
 versionCache['androidx.cursoradapter:cursoradapter'] = '1.1.0-SNAPSHOT'
 versionCache['androidx.customview:customview'] = '1.2.0'
 versionCache['androidx.customview:customview-poolingcontainer'] = '1.1.0'
+versionCache['androidx.datastore:datastore'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.datastore:datastore-android'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.datastore:datastore-core'] = '1.2.0-SNAPSHOT'
 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.datastore:datastore-preferences'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.datastore:datastore-preferences-android'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.datastore:datastore-preferences-core'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.datastore:datastore-preferences-core-android'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.datastore:datastore-preferences-external-protobuf'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.datastore:datastore-preferences-proto'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.documentfile:documentfile'] = '1.1.0'
 versionCache['androidx.drawerlayout:drawerlayout'] = '1.3.0-SNAPSHOT'
 versionCache['androidx.dynamicanimation:dynamicanimation'] = '1.1.0'
@@ -179,9 +187,9 @@
 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.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'
+versionCache['androidx.pdf:pdf-document-service'] = '1.0.0-alpha06'
+versionCache['androidx.pdf:pdf-viewer'] = '1.0.0-alpha06'
+versionCache['androidx.pdf:pdf-viewer-fragment'] = '1.0.0-alpha06'
 versionCache['androidx.preference:preference'] = '1.3.0-SNAPSHOT'
 versionCache['androidx.print:print'] = '1.1.0'
 versionCache['androidx.privacysandbox.ads:ads-adservices'] = '1.1.0-beta11'
@@ -306,7 +314,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13816708/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13828034/artifacts/repository'
     }
     mavenCentral()
 }
@@ -357,6 +365,7 @@
     compileLatest 'androidx.customview:customview:+'
     compileLatest 'androidx.datastore:datastore-android:+'
     compileLatest 'androidx.datastore:datastore-core:+'
+    compileLatest 'androidx.datastore:datastore-preferences:+'
     compileLatest 'androidx.drawerlayout:drawerlayout:+'
     compileLatest 'androidx.dynamicanimation:dynamicanimation:+'
     compileLatest 'androidx.exifinterface:exifinterface:+'
@@ -372,8 +381,10 @@
     compileLatest 'androidx.navigation:navigation-runtime:+'
     compileLatest 'androidx.paging:paging-compose:+'
     compileLatest 'androidx.paging:paging-runtime:+'
-    compileLatest 'androidx.pdf:pdf-viewer:+'
-    compileLatest 'androidx.pdf:pdf-viewer-fragment:+'
+    // Take pdf library 1.0.0-alpha06 until beta release is thoroughly tested.
+    // TODO(https://crbug.com/383610568): Switch to beta version of pdf library once ready.
+    compile 'androidx.pdf:pdf-viewer:1.0.0-alpha06'
+    compile 'androidx.pdf:pdf-viewer-fragment:1.0.0-alpha06'
     compileLatest 'androidx.preference:preference:+'
     // Privacy Sandbox is less stable than others. Use only release versions.
     compile 'androidx.privacysandbox.ads:ads-adservices:1.1.0-beta11'
diff --git a/third_party/androidx/build.gradle.template b/third_party/androidx/build.gradle.template
index e2a02052..6f076e37 100644
--- a/third_party/androidx/build.gradle.template
+++ b/third_party/androidx/build.gradle.template
@@ -87,8 +87,10 @@
     compileLatest 'androidx.navigation:navigation-runtime:+'
     compileLatest 'androidx.paging:paging-compose:+'
     compileLatest 'androidx.paging:paging-runtime:+'
-    compileLatest 'androidx.pdf:pdf-viewer:+'
-    compileLatest 'androidx.pdf:pdf-viewer-fragment:+'
+    // Take pdf library 1.0.0-alpha06 until beta release is thoroughly tested.
+    // TODO(https://crbug.com/383610568): Switch to beta version of pdf library once ready.
+    compile 'androidx.pdf:pdf-viewer:1.0.0-alpha06'
+    compile 'androidx.pdf:pdf-viewer-fragment:1.0.0-alpha06'
     compileLatest 'androidx.preference:preference:+'
     // Privacy Sandbox is less stable than others. Use only release versions.
     compile 'androidx.privacysandbox.ads:ads-adservices:1.1.0-beta11'
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/LICENSE b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
new file mode 100644
index 0000000..c646948
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
@@ -0,0 +1,17 @@
+Name: Preferences DataStore
+Short Name: datastore-preferences-android
+URL: https://developer.android.com/jetpack/androidx/releases/datastore#1.2.0-SNAPSHOT
+Version: 1.2.0-SNAPSHOT
+Update Mechanism: Autoroll
+License: Apache-2.0
+License File: LICENSE
+CPEPrefix: unknown
+Security Critical: yes
+Shipped: yes
+License Android Compatible: yes
+
+Description:
+Android Preferences DataStore
+
+Local Modifications:
+No modifications.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/androidx_datastore_datastore_preferences_android.info b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/androidx_datastore_datastore_preferences_android.info
new file mode 100644
index 0000000..161ffdc
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/androidx_datastore_datastore_preferences_android.info
@@ -0,0 +1,14 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = []
+assets = []
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+manifest_package = "androidx.datastore.preferences"
+resources = []
+subjar_tuples = []
+subjars = []
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/LICENSE b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
new file mode 100644
index 0000000..4590a40
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
@@ -0,0 +1,17 @@
+Name: Preferences DataStore Core
+Short Name: datastore-preferences-core-android
+URL: https://developer.android.com/jetpack/androidx/releases/datastore#1.2.0-SNAPSHOT
+Version: 1.2.0-SNAPSHOT
+Update Mechanism: Autoroll
+License: Apache-2.0
+License File: LICENSE
+CPEPrefix: unknown
+Security Critical: yes
+Shipped: yes
+License Android Compatible: yes
+
+Description:
+Android Preferences DataStore without the Android Dependencies
+
+Local Modifications:
+No modifications.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/androidx_datastore_datastore_preferences_core_android.info b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/androidx_datastore_datastore_preferences_core_android.info
new file mode 100644
index 0000000..3f7465a3
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/androidx_datastore_datastore_preferences_core_android.info
@@ -0,0 +1,14 @@
+# Generated by //build/android/gyp/aar.py
+# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
+
+aidl = []
+assets = []
+has_classes_jar = true
+has_native_libraries = false
+has_proguard_flags = true
+has_r_text_file = false
+is_manifest_empty = true
+manifest_package = "androidx.datastore.preferences.core"
+resources = []
+subjar_tuples = []
+subjars = []
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/LICENSE b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/LICENSE
new file mode 100644
index 0000000..19b305b0
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/LICENSE
@@ -0,0 +1,32 @@
+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.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
new file mode 100644
index 0000000..1021007
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
@@ -0,0 +1,17 @@
+Name: Preferences External Protobuf
+Short Name: datastore-preferences-external-protobuf
+URL: https://developer.android.com/jetpack/androidx/releases/datastore#1.2.0-SNAPSHOT
+Version: 1.2.0-SNAPSHOT
+Update Mechanism: Autoroll
+License: BSD-3-Clause
+License File: LICENSE
+CPEPrefix: unknown
+Security Critical: yes
+Shipped: yes
+License Android Compatible: yes
+
+Description:
+Repackaged proto-lite dependency for use by datastore preferences
+
+Local Modifications:
+No modifications.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/LICENSE b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
new file mode 100644
index 0000000..8b5bcc5
--- /dev/null
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
@@ -0,0 +1,17 @@
+Name: Preferences DataStore Proto
+Short Name: datastore-preferences-proto
+URL: https://developer.android.com/jetpack/androidx/releases/datastore#1.2.0-SNAPSHOT
+Version: 1.2.0-SNAPSHOT
+Update Mechanism: Autoroll
+License: Apache-2.0
+License File: LICENSE
+CPEPrefix: unknown
+Security Critical: yes
+Shipped: yes
+License Android Compatible: yes
+
+Description:
+Jarjar the generated proto for use by datastore-preferences.
+
+Local Modifications:
+No modifications.
diff --git a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
index 5cf50c4e..72ef880 100644
--- a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
@@ -3,7 +3,7 @@
 URL: https://developer.android.com/jetpack/androidx/releases/emoji#1.2.0-SNAPSHOT
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
-License: OFL-1.1, Unicode-DFS-2016, Apache-2.0
+License: Apache-2.0, SIL Open Font License, Version 1.1, Unicode, Inc. License
 License File: LICENSE
 CPEPrefix: unknown
 Security Critical: yes
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium b/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium
index dc19642..f191b3e 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium
@@ -1,7 +1,7 @@
 Name: androidx.pdf:pdf-document-service
 Short Name: pdf-document-service
-URL: https://developer.android.com/jetpack/androidx/releases/pdf#1.0.0-SNAPSHOT
-Version: 1.0.0-SNAPSHOT
+URL: https://developer.android.com/jetpack/androidx/releases/pdf#1.0.0-alpha06
+Version: 1.0.0-alpha06
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/androidx_pdf_pdf_document_service.info b/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/androidx_pdf_pdf_document_service.info
index e0943c17..42bc00fa 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/androidx_pdf_pdf_document_service.info
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/androidx_pdf_pdf_document_service.info
@@ -1,14 +1,11 @@
 # Generated by //build/android/gyp/aar.py
 # To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
 
-aidl = [
-  "aidl/androidx/pdf/annotation/models/AnnotationResult.aidl",
-  "aidl/androidx/pdf/annotation/models/PdfAnnotation.aidl"
-]
+aidl = []
 assets = []
 has_classes_jar = true
 has_native_libraries = false
-has_proguard_flags = true
+has_proguard_flags = false
 has_r_text_file = false
 is_manifest_empty = false
 manifest_package = "androidx.pdf.document.service"
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium
index 32c3a84..2df0f6175 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium
@@ -1,7 +1,7 @@
 Name: androidx.pdf:pdf-viewer
 Short Name: pdf-viewer
-URL: https://developer.android.com/jetpack/androidx/releases/pdf#1.0.0-SNAPSHOT
-Version: 1.0.0-SNAPSHOT
+URL: https://developer.android.com/jetpack/androidx/releases/pdf#1.0.0-alpha06
+Version: 1.0.0-alpha06
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/androidx_pdf_pdf_viewer.info b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/androidx_pdf_pdf_viewer.info
index de901c4..452747e 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/androidx_pdf_pdf_viewer.info
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/androidx_pdf_pdf_viewer.info
@@ -13,7 +13,7 @@
 assets = []
 has_classes_jar = true
 has_native_libraries = false
-has_proguard_flags = true
+has_proguard_flags = false
 has_r_text_file = true
 is_manifest_empty = false
 manifest_package = "androidx.pdf"
@@ -87,11 +87,11 @@
   "res/drawable/shape_textbox.xml",
   "res/drawable/shape_find_in_file.xml",
   "res/drawable/selection_drag_handle_right.xml",
+  "res/drawable/custom_edit_text_cursor.xml",
   "res/drawable/drag_indicator.xml",
   "res/drawable/close_button.xml",
   "res/drawable/shape_oval.xml",
   "res/drawable/keyboard_down.xml",
-  "res/drawable/fast_scroll_thumb_drawable.xml",
   "res/values-gu/values-gu.xml",
   "res/values-te/values-te.xml",
   "res/values-tr/values-tr.xml",
@@ -103,8 +103,7 @@
   "res/layout/find_in_file.xml",
   "res/layout/pdf_search_view.xml",
   "res/layout/search.xml",
-  "res/layout/tool_box_view.xml",
-  "res/layout/pdf_content_layout.xml",
+  "res/layout/toolbox_view.xml",
   "res/layout/dialog_password.xml",
   "res/layout/page_indicator.xml",
   "res/layout/pdf_view_container.xml",
@@ -128,7 +127,6 @@
   "res/values-ka/values-ka.xml",
   "res/values-fr/values-fr.xml",
   "res/values-km/values-km.xml",
-  "res/values-w840dp-v13/values-w840dp-v13.xml",
   "res/values-it/values-it.xml",
   "res/values-ca/values-ca.xml",
   "res/values-hy/values-hy.xml"
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium
index 3b2f106..17962b1 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium
@@ -1,7 +1,7 @@
 Name: androidx.pdf:pdf-viewer-fragment
 Short Name: pdf-viewer-fragment
-URL: https://developer.android.com/jetpack/androidx/releases/pdf#1.0.0-SNAPSHOT
-Version: 1.0.0-SNAPSHOT
+URL: https://developer.android.com/jetpack/androidx/releases/pdf#1.0.0-alpha06
+Version: 1.0.0-alpha06
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/androidx_pdf_pdf_viewer_fragment.info b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/androidx_pdf_pdf_viewer_fragment.info
index 87dc35b..bc6600e 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/androidx_pdf_pdf_viewer_fragment.info
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/androidx_pdf_pdf_viewer_fragment.info
@@ -5,7 +5,7 @@
 assets = []
 has_classes_jar = true
 has_native_libraries = false
-has_proguard_flags = true
+has_proguard_flags = false
 has_r_text_file = true
 is_manifest_empty = true
 manifest_package = "androidx.pdf.viewer.fragment"
diff --git a/third_party/angle b/third_party/angle
index 0aebab7..f94510a 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 0aebab7410358195e4bed006ee19756d43e03963
+Subproject commit f94510ab8d9eb46c9065c6fbd9fa9c14f28b1b45
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 0862575..93c1f745 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -2110,12 +2110,6 @@
 );
 #endif
 
-// Prefetch request properties are updated to be privacy-preserving. See
-// crbug.com/988956.
-BASE_FEATURE(kPrefetchPrivacyChanges,
-             "PrefetchPrivacyChanges",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kPreloadingHeuristicsMLModel,
              "PreloadingHeuristicsMLModel",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -2359,11 +2353,6 @@
 BASE_FEATURE(kSelectiveInOrderScript,
              "SelectiveInOrderScript",
              base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kSelectiveInOrderScriptTarget,
-             "SelectiveInOrderScriptTarget",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-const base::FeatureParam<std::string> kSelectiveInOrderScriptAllowList{
-    &kSelectiveInOrderScriptTarget, "allow_list", ""};
 
 // When enabled, the SubresourceFilter receives calls from the ResourceLoader
 // to perform additional checks against any aliases found from DNS CNAME records
@@ -2378,12 +2367,6 @@
              "ServiceWorkerUpdateDelay",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// When enabled, beacons (and friends) have ResourceLoadPriority::kLow,
-// not ResourceLoadPriority::kVeryLow.
-BASE_FEATURE(kSetLowPriorityForBeacon,
-             "SetLowPriorityForBeacon",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // If enabled, calling setInterval(..., 0) will not clamp to 1ms.
 // Tracking bug: https://crbug.com/402694.
 BASE_FEATURE(kSetIntervalWithoutClamp,
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 17a9a83..38f1ce0 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -269,7 +269,6 @@
     "peerconnection/webrtc_ip_handling_policy.h",
     "peerconnection/webrtc_ip_handling_url_entry.h",
     "performance/largest_contentful_paint_type.h",
-    "performance/performance_timeline_constants.h",
     "permissions/permission_utils.h",
     "permissions_policy/document_policy.h",
     "permissions_policy/document_policy_features.h",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index fb3f04b..5ad3e02 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -1397,8 +1397,6 @@
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kPrefetchFontLookupTables);
 #endif
 
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kPrefetchPrivacyChanges);
-
 // If enabled, the machine learning model will be employed to predict the next
 // click for speculation-rule based pre-loadings.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kPreloadingHeuristicsMLModel);
@@ -1598,7 +1596,6 @@
 // scripts are selectively applied via the allowlist provided from the feature
 // param. See https://crbug.com/1356396
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSelectiveInOrderScript);
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSelectiveInOrderScriptTarget);
 // Note: declared without BASE_DECLARE_FEATURE_PARAM because the production code
 // gets this value only once to construct a static local variable.
 BLINK_COMMON_EXPORT extern const base::FeatureParam<std::string>
@@ -1611,8 +1608,6 @@
 
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerUpdateDelay);
 
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSetLowPriorityForBeacon);
-
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSetIntervalWithoutClamp);
 
 // If enabled, the shared storage worklet threads (on the same renderer process)
diff --git a/third_party/blink/public/common/performance/performance_timeline_constants.h b/third_party/blink/public/common/performance/performance_timeline_constants.h
deleted file mode 100644
index 1f4dbbc..0000000
--- a/third_party/blink/public/common/performance/performance_timeline_constants.h
+++ /dev/null
@@ -1,26 +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 THIRD_PARTY_BLINK_PUBLIC_COMMON_PERFORMANCE_PERFORMANCE_TIMELINE_CONSTANTS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_PERFORMANCE_PERFORMANCE_TIMELINE_CONSTANTS_H_
-
-#include "base/time/time.h"
-
-namespace blink {
-
-inline constexpr uint32_t kSoftNavigationCountDefaultValue = 0;
-
-// The default value (0) indicates the absence of a navigation id.
-// It's used for initialization and for cases when there's no navigation id
-// e.g. in service workers. See also navigation_id_generator.h.
-inline constexpr uint32_t kNavigationIdDefaultValue = 0;
-
-struct SoftNavigationMetrics {
-  uint32_t count = kSoftNavigationCountDefaultValue;
-  base::TimeDelta start_time;
-  base::TimeDelta first_contentful_paint;
-  uint32_t navigation_id = kNavigationIdDefaultValue;
-};
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_PERFORMANCE_PERFORMANCE_TIMELINE_CONSTANTS_H_
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index ac8cd33..4faa51b 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -6362,7 +6362,7 @@
       # https://github.com/WICG/private-network-access/blob/main/permission_prompt/explainer.md
       PrivateNetworkAccessPermissionDenied
       # Request was a local network request and is denied by user permission.
-      # https://github.com/explainers-by-googlers/local-network-access
+      # https://wicg.github.io/local-network-access/
       LocalNetworkAccessPermissionDenied
 
   type CorsErrorStatus extends object
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 63410b5..adc8d96d 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -100,6 +100,7 @@
     "file_system_access/file_system_access_manager.mojom",
     "file_system_access/file_system_access_observer.mojom",
     "file_system_access/file_system_access_observer_host.mojom",
+    "file_system_access/file_system_access_permission_mode.mojom",
     "file_system_access/file_system_access_transfer_token.mojom",
     "filesystem/file_system.mojom",
     "font_access/font_access.mojom",
diff --git a/third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom b/third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom
index 4946d39..9c75d69 100644
--- a/third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom
+++ b/third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom
@@ -8,6 +8,7 @@
 import "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom";
+import "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom";
 import "third_party/blink/public/mojom/permissions/permission_status.mojom";
 
 // Union representing either a file or a directory handle. Used in APIs that
@@ -43,13 +44,13 @@
 // our paths really aren't base::FilePath, but instead are virtual paths).
 interface FileSystemAccessDirectoryHandle {
   // Queries the current permission status for this handle.
-  GetPermissionStatus(bool writable) => (PermissionStatus status);
+  GetPermissionStatus(FileSystemAccessPermissionMode mode) => (PermissionStatus status);
 
   // Requests read and/or write permission for this handle. Returns the new
   // permission status for this handle.
   // TODO(https://crbug.com/1327821): Replace this with expected<T, E> if/when
   // it becomes available for mojom.
-  RequestPermission(bool writable) => (FileSystemAccessError result, PermissionStatus status);
+  RequestPermission(FileSystemAccessPermissionMode mode) => (FileSystemAccessError result, PermissionStatus status);
 
   // Returns a file with the given `basename` that is a child of this
   // directory. If no such file exists, and `create` is true, the file is first
diff --git a/third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom b/third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom
index 66516f3..813ea649 100644
--- a/third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom
+++ b/third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom
@@ -15,6 +15,7 @@
 import "third_party/blink/public/mojom/file_system_access/file_system_access_file_delegate_host.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_file_writer.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom";
+import "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom";
 import "third_party/blink/public/mojom/permissions/permission_status.mojom";
 
 // Representation of a regular file for an AccessHandle.
@@ -67,13 +68,13 @@
 // API.
 interface FileSystemAccessFileHandle {
   // Queries the current permission status for this handle.
-  GetPermissionStatus(bool writable) => (PermissionStatus status);
+  GetPermissionStatus(FileSystemAccessPermissionMode mode) => (PermissionStatus status);
 
   // Requests read and/or write permission for this handle. Returns the new
   // permission status for this handle.
   // TODO(https://crbug.com/1327821): Replace this with expected<T, E> if/when
   // it becomes available for mojom.
-  RequestPermission(bool writable) => (FileSystemAccessError result, PermissionStatus status);
+  RequestPermission(FileSystemAccessPermissionMode mode) => (FileSystemAccessError result, PermissionStatus status);
 
   // Returns a blob representing the current state of this file.
   // TODO(https://crbug.com/1327821): Replace this with expected<T, E> if/when
diff --git a/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom b/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom
index 66165f9..8e7e34c 100644
--- a/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom
+++ b/third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom
@@ -10,6 +10,7 @@
 import "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_observer_host.mojom";
+import "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom";
 import "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom";
 
 enum WellKnownDirectory {
@@ -21,13 +22,6 @@
   kDirVideos,
 };
 
-// Represents the permission mode that can be requested for a file system entry.
-// TODO(crbug.com/40276567): Support Write mode.
-enum FileSystemAccessPermissionMode {
-  kRead,
-  kReadWrite,
-};
-
 // Struct to represent individual options for types of files that are accepted
 // by calls to ChooseEntry. Each type has an optional description, and any
 // number of mime types and/or extensions.
diff --git a/third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom b/third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom
new file mode 100644
index 0000000..13a20abc
--- /dev/null
+++ b/third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom
@@ -0,0 +1,12 @@
+// 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.
+
+module blink.mojom;
+
+// Represents the permission mode that can be requested for a file system entry.
+enum FileSystemAccessPermissionMode {
+  kRead,
+  kReadWrite,
+  kWrite,
+};
diff --git a/third_party/blink/public/mojom/page/prerender_page_param.mojom b/third_party/blink/public/mojom/page/prerender_page_param.mojom
index b6670a75..a45c0df 100644
--- a/third_party/blink/public/mojom/page/prerender_page_param.mojom
+++ b/third_party/blink/public/mojom/page/prerender_page_param.mojom
@@ -17,4 +17,8 @@
   // If true, dry run paint phase to pre-build a paint tree for the page, so
   // then the intermediate result can be reused after activation.
   bool should_prepare_paint_tree;
+
+  // If true, pauses JavaScript execution until the page is activated.
+  // TODO(crbug.com/428500219): Allow upgrading to a full prerender.
+  bool should_pause_javascript_execution;
 };
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index be5a5e966..d5d1f85a 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -3222,7 +3222,8 @@
   kV8URLPattern_Exec_Method = 3961,
   kSameSiteCookieInclusionChangedByCrossSiteRedirect = 3962,
   // The items above roughly this point are available in the M93 branch.
-  kOBSOLETE_BlobStoreAccessAcrossAgentClustersInResolveAsURLLoaderFactory = 3963,
+  kOBSOLETE_BlobStoreAccessAcrossAgentClustersInResolveAsURLLoaderFactory =
+      3963,
   kOBSOLETE_BlobStoreAccessAcrossAgentClustersInResolveForNavigation = 3964,
   kTapDelayEnabled = 3965,
   kV8URLPattern_CompareComponent_Method = 3966,
@@ -3538,7 +3539,7 @@
   kSharedStorageAPI_SelectURL_Method = 4269,
   kSharedStorageAPI_Run_Method = 4270,
   kViewTimelineConstructor = 4271,
-  kH1UserAgentFontSizeInSectionApplied = 4272,
+  kOBSOLETE_H1UserAgentFontSizeInSectionApplied = 4272,
   kOBSOLETE_kV8PendingBeacon_Constructor = 4273,
   kOBSOLETE_kV8PendingBeacon_Url_AttributeGetter = 4274,
   kOBSOLETE_kV8PendingBeacon_Url_AttributeSetter = 4275,
@@ -4919,6 +4920,7 @@
   kCanvasFallbackElementContent = 5609,
   kAutofillMaybeSyntheticSelect = 5610,
   kAutofillSyntheticSelect = 5611,
+  kFetchRetry = 5612,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots. Also don't add extra
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 92682c4..5c1c325d 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -51,7 +51,6 @@
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
 #include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/common/subresource_load_metrics.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
@@ -95,6 +94,7 @@
 #include "third_party/blink/public/web/web_navigation_params.h"
 #include "third_party/blink/public/web/web_navigation_policy.h"
 #include "third_party/blink/public/web/web_navigation_type.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_event.h"
 #include "ui/accessibility/ax_location_and_scroll_updates.h"
@@ -647,7 +647,8 @@
   virtual void DidObserveNewFeatureUsage(const UseCounterFeature&) {}
 
   // A new soft navigation was observed.
-  virtual void DidObserveSoftNavigation(blink::SoftNavigationMetrics metrics) {}
+  virtual void DidObserveSoftNavigation(
+      blink::SoftNavigationMetricsForReporting metrics) {}
 
   // Reports that visible elements in the frame shifted (bit.ly/lsm-explainer).
   virtual void DidObserveLayoutShift(double score, bool after_input_or_scroll) {
diff --git a/third_party/blink/public/web/web_performance_metrics_for_reporting.h b/third_party/blink/public/web/web_performance_metrics_for_reporting.h
index 789442c..c9abb34 100644
--- a/third_party/blink/public/web/web_performance_metrics_for_reporting.h
+++ b/third_party/blink/public/web/web_performance_metrics_for_reporting.h
@@ -35,12 +35,21 @@
   double image_bpp = 0.0;
   double text_paint_time = 0;
   uint64_t text_paint_size = 0;
-  base::TimeTicks paint_time = base::TimeTicks();
+  base::TimeTicks paint_time;
   std::optional<WebURLRequest::Priority> image_request_priority = std::nullopt;
   // The unclamped paint time of the largest content (image/text).
   std::optional<base::TimeTicks> merged_unclamped_paint_time = std::nullopt;
 };
 
+struct SoftNavigationMetricsForReporting {
+  uint32_t count = 0;
+  base::TimeDelta start_time;
+  base::TimeDelta first_contentful_paint;
+  // For the mechanism that generates these ids, see
+  // third_party/blink/renderer/core/timing/navigation_id_generator.h.
+  uint32_t navigation_id = 0;
+};
+
 // This class is used for reporting purposes (e.g. ukm) of non-web-exposed
 // metrics.
 class BLINK_EXPORT WebPerformanceMetricsForReporting {
diff --git a/third_party/blink/renderer/README.md b/third_party/blink/renderer/README.md
index a071e78..e5a9087 100644
--- a/third_party/blink/renderer/README.md
+++ b/third_party/blink/renderer/README.md
@@ -51,7 +51,7 @@
 
 For example, `platform/scheduler` implements a task scheduler for all tasks
 posted by Blink, while `platform/wtf` implements Blink-specific containers
-(e.g., `WTF::Vector`, `WTF::HashTable`, `WTF::String`).
+(e.g., `blink::Vector`, `blink::HashMap`, `blink::String`).
 
 ### `core` vs `modules` vs `platform` split
 
@@ -135,7 +135,7 @@
 ### Type dependencies
 
 Member variables of the following types are strongly discouraged in Blink:
-  - STL strings and containers. Use `WTF::String` and WTF containers instead.
+  - STL strings and containers. Use `blink::String` and WTF containers instead.
   - `GURL` and `url::Origin`. Use `KURL` and `SecurityOrigin` respectively.
   - Any `//base` type which has a matching type in `platform/wtf`. The number of
   duplicated types between WTF and base is continuously shrinking,
@@ -147,7 +147,7 @@
 of these types when convenient, as long as the result is not stored
 in a member variable (with exceptions described below).
 For example, calling an utility function on an `std::string` which came
-from `//net` and then converting to `WTF::String` to store in a field
+from `//net` and then converting to `blink::String` to store in a field
 is allowed.
 
 We try to share as much code between Chromium and Blink as possible,
@@ -215,4 +215,3 @@
 
 If you have any questions about the directory architecture and dependencies,
 reach out to platform-architecture-dev@chromium.org!
-
diff --git a/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py b/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
index c81db2ab..004f883d 100755
--- a/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
+++ b/third_party/blink/renderer/build/scripts/core/css/make_style_shorthands.py
@@ -125,11 +125,19 @@
             for longhand_enum_key in longhand_enum_keys:
                 self._longhand_dictionary[longhand_enum_key].append(property_)
 
-        for longhands in self._longhand_dictionary.values():
-            # Sort first by number of longhands in decreasing order, then
-            # alphabetically
-            longhands.sort(key=lambda property_: (-len(property_.longhands),
-                                                  property_.name.original))
+        for shorthands in self._longhand_dictionary.values():
+            # https://drafts.csswg.org/cssom/#concept-shorthands-preferred-order
+            def shorthand_order(shorthand):
+                name = shorthand.ultimate_property.name.original
+                if name.startswith("-webkit-"):
+                    hyphen_order = 1
+                elif name.startswith("-"):
+                    hyphen_order = 2
+                else:
+                    hyphen_order = 0
+                return (-len(shorthand.longhands), hyphen_order, name)
+
+            shorthands.sort(key=shorthand_order)
 
     @template_expander.use_jinja(
         'core/css/templates/style_property_shorthand.cc.tmpl')
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index 5fca188f..9a508e0 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -320,31 +320,6 @@
     state_.SetRejectedLegacyOverlapping();
   }
 
-  // TOOD(crbug.com/1334570):
-  //
-  // Count applied H1 font-size from html.css UA stylesheet where H1 is inside
-  // a sectioning element matching selectors like:
-  //
-  // :-webkit-any(article,aside,nav,section) h1 { ... }
-  //
-  if (state_.GetElement().HasTagName(html_names::kH1Tag)) {
-    if (CascadePriority* priority =
-            map_.Find(GetCSSPropertyFontSize().GetCSSPropertyName())) {
-      if (priority->GetOrigin() != CascadeOrigin::kUserAgent) {
-        return;
-      }
-      const CSSValue* value = ValueAt(match_result_, priority->GetPosition());
-      if (const auto* numeric = DynamicTo<CSSNumericLiteralValue>(value)) {
-        DCHECK(numeric->GetType() == CSSNumericLiteralValue::UnitType::kEms);
-        if (numeric->DoubleValue() != 2.0) {
-          Deprecation::CountDeprecation(
-              GetDocument().GetExecutionContext(),
-              WebFeature::kH1UserAgentFontSizeInSectionApplied);
-        }
-      }
-    }
-  }
-
   ApplyUnresolvedEnv(resolver);
 }
 
diff --git a/third_party/blink/renderer/core/css/rule_set_diff.cc b/third_party/blink/renderer/core/css/rule_set_diff.cc
index 0dfe181d..a8215699 100644
--- a/third_party/blink/renderer/core/css/rule_set_diff.cc
+++ b/third_party/blink/renderer/core/css/rule_set_diff.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/renderer/core/css/media_query_evaluator.h"
 #include "third_party/blink/renderer/core/css/rule_set.h"
 #include "third_party/blink/renderer/core/css/style_rule.h"
+#include "v8/include/cppgc/garbage-collected.h"
 
 namespace blink {
 
@@ -41,4 +42,10 @@
   return ruleset;
 }
 
+void RuleSetDiff::Trace(Visitor* visitor) const {
+  visitor->Trace(old_ruleset_);
+  visitor->Trace(new_ruleset_);
+  visitor->Trace(changed_rules_);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/rule_set_diff.h b/third_party/blink/renderer/core/css/rule_set_diff.h
index d2325aaf..19ebbd8 100644
--- a/third_party/blink/renderer/core/css/rule_set_diff.h
+++ b/third_party/blink/renderer/core/css/rule_set_diff.h
@@ -83,11 +83,7 @@
     return old_ruleset == old_ruleset_ && new_ruleset == new_ruleset_;
   }
 
-  void Trace(Visitor* visitor) const {
-    visitor->Trace(old_ruleset_);
-    visitor->Trace(new_ruleset_);
-    visitor->Trace(changed_rules_);
-  }
+  void Trace(Visitor* visitor) const;
 
   // Creates a RuleSet that contains only those rules in “old_ruleset_”
   // and “new_ruleset_” that are covered by a change given to AddDiff().
diff --git a/third_party/blink/renderer/core/css/style_sheet_contents.h b/third_party/blink/renderer/core/css/style_sheet_contents.h
index 71b5b7b..ef0d7c7 100644
--- a/third_party/blink/renderer/core/css/style_sheet_contents.h
+++ b/third_party/blink/renderer/core/css/style_sheet_contents.h
@@ -25,9 +25,8 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
-#include "third_party/blink/renderer/core/css/rule_set.h"
 #include "third_party/blink/renderer/core/css/rule_set_diff.h"
-#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
+#include "third_party/blink/renderer/core/css/style_rule.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/loader/fetch/render_blocking_behavior.h"
@@ -43,10 +42,13 @@
 namespace blink {
 
 class CSSStyleSheet;
+class CSSStyleSheetResource;
 class Document;
+class MediaQueryEvaluator;
 class Node;
 class StyleRuleBase;
 class StyleRuleFontFace;
+class RuleSet;
 class RuleSetDiff;
 class StyleRuleImport;
 class StyleRuleNamespace;
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc
index 2fa3045..d5bd0d9 100644
--- a/third_party/blink/renderer/core/dom/container_node.cc
+++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -74,6 +74,7 @@
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_text.h"
 #include "third_party/blink/renderer/core/layout/layout_text_combine.h"
+#include "third_party/blink/renderer/core/patching/patch_supplement.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/timing/soft_navigation_heuristics.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -1888,4 +1889,9 @@
                       shadow_root_inclusion);
 }
 
+WritableStream* ContainerNode::patchSelf(ScriptState* script_state) {
+  return PatchSupplement::From(GetDocument())
+      ->CreateSinglePatchStream(script_state, *this);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/container_node.h b/third_party/blink/renderer/core/dom/container_node.h
index b445fcaa..25cb0177 100644
--- a/third_party/blink/renderer/core/dom/container_node.h
+++ b/third_party/blink/renderer/core/dom/container_node.h
@@ -42,8 +42,10 @@
 class GetHTMLOptions;
 class HTMLCollection;
 class RadioNodeList;
+class ScriptState;
 class StyleRecalcContext;
 class WhitespaceAttacher;
+class WritableStream;
 
 using StaticElementList = StaticNodeTypeList<Element>;
 
@@ -470,6 +472,8 @@
   // only.
   String getHTML(const GetHTMLOptions*, ExceptionState&) const;
 
+  WritableStream* patchSelf(ScriptState*);
+
   // DocumentOrElementEventHandlers:
   // These event listeners are only actually web-exposed on interfaces that
   // include the DocumentOrElementEventHandlers mixin in their idl.
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 8335ef0..15e608b 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8928,8 +8928,9 @@
   if (autofocus_processed_flag_)
     return;
   wtf_size_t index = autofocus_candidates_.Find(&element);
-  if (index != WTF::kNotFound)
+  if (index != kNotFound) {
     autofocus_candidates_.EraseAt(index);
+  }
   autofocus_candidates_.push_back(element);
 }
 
diff --git a/third_party/blink/renderer/core/dom/document_statistics_collector.cc b/third_party/blink/renderer/core/dom/document_statistics_collector.cc
index 593a45e..394c541 100644
--- a/third_party/blink/renderer/core/dom/document_statistics_collector.cc
+++ b/third_party/blink/renderer/core/dom/document_statistics_collector.cc
@@ -73,8 +73,8 @@
   const String& classes = element.GetClassAttribute();
   const String& id = element.GetIdAttribute();
   for (const String& word : words) {
-    if (classes.DeprecatedFindIgnoringCase(word) != WTF::kNotFound ||
-        id.DeprecatedFindIgnoringCase(word) != WTF::kNotFound) {
+    if (classes.DeprecatedFindIgnoringCase(word) != kNotFound ||
+        id.DeprecatedFindIgnoringCase(word) != kNotFound) {
       return true;
     }
   }
diff --git a/third_party/blink/renderer/core/dom/parent_node.idl b/third_party/blink/renderer/core/dom/parent_node.idl
index 4011423..d02cc7ca 100644
--- a/third_party/blink/renderer/core/dom/parent_node.idl
+++ b/third_party/blink/renderer/core/dom/parent_node.idl
@@ -42,4 +42,5 @@
 
   [Affects=Nothing, RaisesException] Element? querySelector(DOMString selectors);
   [Affects=Nothing, NewObject, RaisesException] NodeList querySelectorAll(DOMString selectors);
+  [RuntimeEnabled=DocumentPatching, CallWith=ScriptState] WritableStream patchSelf();
 };
diff --git a/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc b/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
index 34db214..b4a4ea2 100644
--- a/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
@@ -54,8 +54,9 @@
   wtf_size_t start = 0;
   while (true) {
     wtf_size_t pos = str.Find(pattern, start);
-    if (pos == WTF::kNotFound)
+    if (pos == kNotFound) {
       break;
+    }
     matches++;
     start = pos + size;
   }
@@ -137,27 +138,27 @@
       GenerateMHTMLFromHtml("http://www.test.com", "script_in_attributes.html");
 
   // These scripting attributes should be removed.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("onload="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("ONLOAD="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("onclick="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("href="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("from="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("to="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("javascript:"));
+  EXPECT_EQ(kNotFound, mhtml.Find("onload="));
+  EXPECT_EQ(kNotFound, mhtml.Find("ONLOAD="));
+  EXPECT_EQ(kNotFound, mhtml.Find("onclick="));
+  EXPECT_EQ(kNotFound, mhtml.Find("href="));
+  EXPECT_EQ(kNotFound, mhtml.Find("from="));
+  EXPECT_EQ(kNotFound, mhtml.Find("to="));
+  EXPECT_EQ(kNotFound, mhtml.Find("javascript:"));
 
   // These non-scripting attributes should remain intact.
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("class="));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("id="));
+  EXPECT_NE(kNotFound, mhtml.Find("class="));
+  EXPECT_NE(kNotFound, mhtml.Find("id="));
 
   // srcdoc attribute of frame element should be replaced with src attribute.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcdoc="));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("src="));
+  EXPECT_EQ(kNotFound, mhtml.Find("srcdoc="));
+  EXPECT_NE(kNotFound, mhtml.Find("src="));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, RemoveOtherAttributes) {
   String mhtml =
       GenerateMHTMLFromHtml("http://www.test.com", "remove_attributes.html");
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("ping="));
+  EXPECT_EQ(kNotFound, mhtml.Find("ping="));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, RemoveHiddenElements) {
@@ -165,22 +166,22 @@
       GenerateMHTMLFromHtml("http://www.test.com", "hidden_elements.html");
 
   // The element with hidden attribute should be removed.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<p id=3D\"hidden_id\""));
+  EXPECT_EQ(kNotFound, mhtml.Find("<p id=3D\"hidden_id\""));
 
   // The hidden form element should be removed.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<input type=3D\"hidden\""));
+  EXPECT_EQ(kNotFound, mhtml.Find("<input type=3D\"hidden\""));
 
   // The style element should be converted to link element.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<style"));
+  EXPECT_EQ(kNotFound, mhtml.Find("<style"));
 
   // All other hidden elements should not be removed.
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<html"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<head"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<title"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<h1"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<h2"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<datalist"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<option"));
+  EXPECT_NE(kNotFound, mhtml.Find("<html"));
+  EXPECT_NE(kNotFound, mhtml.Find("<head"));
+  EXPECT_NE(kNotFound, mhtml.Find("<title"));
+  EXPECT_NE(kNotFound, mhtml.Find("<h1"));
+  EXPECT_NE(kNotFound, mhtml.Find("<h2"));
+  EXPECT_NE(kNotFound, mhtml.Find("<datalist"));
+  EXPECT_NE(kNotFound, mhtml.Find("<option"));
   // One for meta in head and another for meta in body.
   EXPECT_EQ(2, MatchSubstring(mhtml, "<meta", 5));
   // Two for original link elements: one in head and another in body.
@@ -188,10 +189,10 @@
   EXPECT_EQ(4, MatchSubstring(mhtml, "<link", 5));
 
   // These visible elements should remain intact.
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<p id=3D\"visible_id\""));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<form"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<input type=3D\"text\""));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<div"));
+  EXPECT_NE(kNotFound, mhtml.Find("<p id=3D\"visible_id\""));
+  EXPECT_NE(kNotFound, mhtml.Find("<form"));
+  EXPECT_NE(kNotFound, mhtml.Find("<input type=3D\"text\""));
+  EXPECT_NE(kNotFound, mhtml.Find("<div"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, RemoveIframeInHead) {
@@ -226,24 +227,23 @@
       GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html");
 
   // srcset and sizes attributes should be skipped.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("sizes="));
+  EXPECT_EQ(kNotFound, mhtml.Find("srcset="));
+  EXPECT_EQ(kNotFound, mhtml.Find("sizes="));
 
   // src attribute with original URL should be preserved.
   EXPECT_EQ(2,
             MatchSubstring(mhtml, "src=3D\"http://www.test.com/1x.png\"", 34));
 
   // The image resource for original URL should be attached.
-  EXPECT_NE(WTF::kNotFound,
+  EXPECT_NE(kNotFound,
             mhtml.Find("Content-Location: http://www.test.com/1x.png"));
 
   // Width and height attributes should be set when none is present in <img>.
-  EXPECT_NE(WTF::kNotFound,
-            mhtml.Find("id=3D\"i1\" width=3D\"6\" height=3D\"6\">"));
+  EXPECT_NE(kNotFound, mhtml.Find("id=3D\"i1\" width=3D\"6\" height=3D\"6\">"));
 
   // Height attribute should not be set if width attribute is already present in
   // <img>
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
+  EXPECT_NE(kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, ImageLoadedFromSrcForNormalDPI) {
@@ -256,20 +256,20 @@
       GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html");
 
   // srcset and sizes attributes should be skipped.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset="));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("sizes="));
+  EXPECT_EQ(kNotFound, mhtml.Find("srcset="));
+  EXPECT_EQ(kNotFound, mhtml.Find("sizes="));
 
   // src attribute with original URL should be preserved.
   EXPECT_EQ(2,
             MatchSubstring(mhtml, "src=3D\"http://www.test.com/1x.png\"", 34));
 
   // The image resource for original URL should be attached.
-  EXPECT_NE(WTF::kNotFound,
+  EXPECT_NE(kNotFound,
             mhtml.Find("Content-Location: http://www.test.com/1x.png"));
 
   // New width and height attributes should not be set.
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i1\">"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
+  EXPECT_NE(kNotFound, mhtml.Find("id=3D\"i1\">"));
+  EXPECT_NE(kNotFound, mhtml.Find("id=3D\"i2\" width=3D\"8\">"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, RemovePopupOverlayIfRequested) {
@@ -278,8 +278,8 @@
   String mhtml =
       WebFrameSerializerTestHelper::GenerateMHTMLWithPopupOverlayRemoved(
           MainFrameImpl());
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("class=3D\"modal"));
+  EXPECT_EQ(kNotFound, mhtml.Find("class=3D\"overlay"));
+  EXPECT_EQ(kNotFound, mhtml.Find("class=3D\"modal"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, PopupOverlayNotFound) {
@@ -292,8 +292,8 @@
 TEST_F(WebFrameSerializerSanitizationTest, KeepPopupOverlayIfNotRequested) {
   WebView()->MainFrameViewWidget()->Resize(gfx::Size(500, 500));
   String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "popup.html");
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"overlay"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("class=3D\"modal"));
+  EXPECT_NE(kNotFound, mhtml.Find("class=3D\"overlay"));
+  EXPECT_NE(kNotFound, mhtml.Find("class=3D\"modal"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, LinkIntegrity) {
@@ -309,27 +309,26 @@
   EXPECT_TRUE(
       mhtml.Contains("<link rel=3D\"stylesheet\" "
                      "href=3D\"http://www.test.com/beautifull.css\">"));
-  EXPECT_EQ(WTF::kNotFound,
-            mhtml.Find("http://www.test.com/integrityfail.css"));
+  EXPECT_EQ(kNotFound, mhtml.Find("http://www.test.com/integrityfail.css"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, RemoveElements) {
   String mhtml =
       GenerateMHTMLFromHtml("http://www.test.com", "remove_elements.html");
 
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<script"));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<noscript"));
+  EXPECT_EQ(kNotFound, mhtml.Find("<script"));
+  EXPECT_EQ(kNotFound, mhtml.Find("<noscript"));
 
   // Only the meta element containing "Content-Security-Policy" is removed.
   // Other meta elements should be preserved.
-  EXPECT_EQ(WTF::kNotFound,
+  EXPECT_EQ(kNotFound,
             mhtml.Find("<meta http-equiv=3D\"Content-Security-Policy"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<meta name=3D\"description"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<meta http-equiv=3D\"refresh"));
+  EXPECT_NE(kNotFound, mhtml.Find("<meta name=3D\"description"));
+  EXPECT_NE(kNotFound, mhtml.Find("<meta http-equiv=3D\"refresh"));
 
   // If an element is removed, its children should also be skipped.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<select"));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("<option"));
+  EXPECT_EQ(kNotFound, mhtml.Find("<select"));
+  EXPECT_EQ(kNotFound, mhtml.Find("<option"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, ShadowDOM) {
@@ -342,13 +341,13 @@
   String mhtml = WebFrameSerializerTestHelper::GenerateMHTML(MainFrameImpl());
 
   // Template with special attribute should be created for each shadow DOM tree.
-  EXPECT_NE(WTF::kNotFound,
+  EXPECT_NE(kNotFound,
             mhtml.Find("<template shadowmode=3D\"open\" shadowdelegatesfocus"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("<template shadowmode=3D\"closed\">"));
+  EXPECT_NE(kNotFound, mhtml.Find("<template shadowmode=3D\"closed\">"));
 
   // The special attribute present in the original page should be removed.
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("shadowmode=3D\"foo\">"));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("shadowdelegatesfocus=3D\"bar\">"));
+  EXPECT_EQ(kNotFound, mhtml.Find("shadowmode=3D\"foo\">"));
+  EXPECT_EQ(kNotFound, mhtml.Find("shadowdelegatesfocus=3D\"bar\">"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, StyleElementsWithDynamicCSS) {
@@ -356,9 +355,9 @@
                                        "style_element_with_dynamic_css.html");
 
   // The dynamically updated CSS rules should be preserved.
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("div { color: blue; }"));
-  EXPECT_NE(WTF::kNotFound, mhtml.Find("p { color: red; }"));
-  EXPECT_EQ(WTF::kNotFound, mhtml.Find("h1 { color: green; }"));
+  EXPECT_NE(kNotFound, mhtml.Find("div { color: blue; }"));
+  EXPECT_NE(kNotFound, mhtml.Find("p { color: red; }"));
+  EXPECT_EQ(kNotFound, mhtml.Find("h1 { color: green; }"));
 }
 
 TEST_F(WebFrameSerializerSanitizationTest, PictureElement) {
@@ -375,9 +374,9 @@
   EXPECT_EQ(2, MatchSubstring(mhtml, "srcset=", 7));
 
   // 2x.png resource should be added.
-  EXPECT_NE(WTF::kNotFound,
+  EXPECT_NE(kNotFound,
             mhtml.Find("Content-Location: http://www.test.com/2x.png"));
-  EXPECT_EQ(WTF::kNotFound,
+  EXPECT_EQ(kNotFound,
             mhtml.Find("Content-Location: http://www.test.com/1x.png"));
 }
 
@@ -391,9 +390,9 @@
       GenerateMHTMLFromHtml("http://www.test.com", "image_in_plugin.html");
 
   // Image resources for both object and embed elements should be added.
-  EXPECT_NE(WTF::kNotFound,
+  EXPECT_NE(kNotFound,
             mhtml.Find("Content-Location: http://www.test.com/1x.png"));
-  EXPECT_NE(WTF::kNotFound,
+  EXPECT_NE(kNotFound,
             mhtml.Find("Content-Location: http://www.test.com/2x.png"));
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index aae07d5..d4bc484 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -653,6 +653,8 @@
         prerender_param->should_warm_up_compositor);
     page_->SetShouldPreparePaintTreeOnPrerender(
         prerender_param->should_prepare_paint_tree);
+    page_->SetShouldPauseJavaScriptExecutionOnPrerender(
+        prerender_param->should_pause_javascript_execution);
   }
 
   if (fenced_frame_mode && features::IsFencedFramesEnabled()) {
diff --git a/third_party/blink/renderer/core/fetch/request.cc b/third_party/blink/renderer/core/fetch/request.cc
index 0499390d..68c7283 100644
--- a/third_party/blink/renderer/core/fetch/request.cc
+++ b/third_party/blink/renderer/core/fetch/request.cc
@@ -656,6 +656,7 @@
     request->SetKeepalive(init->keepalive());
 
   if (init->hasRetryOptions()) {
+    UseCounter::Count(execution_context, WebFeature::kFetchRetry);
     network::FetchRetryOptions options;
     RetryOptions* retry_options = init->retryOptions();
     options.max_attempts = retry_options->maxAttempts();
diff --git a/third_party/blink/renderer/core/fileapi/file.cc b/third_party/blink/renderer/core/fileapi/file.cc
index 3c6c049..c5022ad 100644
--- a/third_party/blink/renderer/core/fileapi/file.cc
+++ b/third_party/blink/renderer/core/fileapi/file.cc
@@ -54,7 +54,7 @@
                                          File::ContentTypeLookupPolicy policy) {
   String type;
   wtf_size_t index = name.ReverseFind('.');
-  if (index != WTF::kNotFound) {
+  if (index != kNotFound) {
     if (policy == File::kWellKnownContentTypes) {
       type = MIMETypeRegistry::GetWellKnownMIMETypeForExtension(
           name.Substring(index + 1));
diff --git a/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
index 40aeae7..56018ae 100644
--- a/third_party/blink/renderer/core/frame/ad_tracker_test.cc
+++ b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -875,6 +875,183 @@
   EXPECT_TRUE(image_element->IsAdRelated());
 }
 
+TEST_F(AdTrackerSimTest, PromiseResolveDetected) {
+  const char kAdScriptUrl[] = "https://example.com/ad_script.js";
+  const char kImageUrl[] = "https://example.com/image.gif";
+  SimSubresourceRequest image(kImageUrl, "image/gif");
+  SimSubresourceRequest ad_script(kAdScriptUrl, "text/javascript");
+
+  main_resource_->Complete("<body></body><script src=ad_script.js></script>");
+
+  ad_script.Complete(R"SCRIPT(
+    Promise.resolve().then( () => {
+      image = document.createElement("img");
+      image.src = "image.gif";
+      document.body.appendChild(image);
+    });
+    )SCRIPT");
+
+  ad_tracker_->WaitForSubresource(kImageUrl);
+
+  // Put the gif bytes in a Vector to avoid difficulty with
+  // non null-terminated char*.
+  Vector<char> gif;
+  gif.AppendSpan(base::span(kSmallGifData));
+
+  image.Complete(gif);
+
+  EXPECT_TRUE(
+      IsKnownAdScript(GetDocument().GetExecutionContext(), kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kImageUrl));
+}
+
+TEST_F(AdTrackerSimTest, PromiseRejectDetected) {
+  const char kAdScriptUrl[] = "https://example.com/ad_script.js";
+  const char kImageUrl[] = "https://example.com/image.gif";
+  SimSubresourceRequest image(kImageUrl, "image/gif");
+  SimSubresourceRequest ad_script(kAdScriptUrl, "text/javascript");
+
+  main_resource_->Complete("<body></body><script src=ad_script.js></script>");
+
+  ad_script.Complete(R"SCRIPT(
+    Promise.reject().catch( () => {
+      image = document.createElement("img");
+      image.src = "image.gif";
+      document.body.appendChild(image);
+    });
+    )SCRIPT");
+
+  ad_tracker_->WaitForSubresource(kImageUrl);
+
+  // Put the gif bytes in a Vector to avoid difficulty with
+  // non null-terminated char*.
+  Vector<char> gif;
+  gif.AppendSpan(base::span(kSmallGifData));
+
+  image.Complete(gif);
+
+  EXPECT_TRUE(
+      IsKnownAdScript(GetDocument().GetExecutionContext(), kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kImageUrl));
+}
+
+TEST_F(AdTrackerSimTest, PromiseChain) {
+  const char kAdScriptUrl[] = "https://example.com/ad_script.js";
+  const char kImageUrl[] = "https://example.com/image.gif";
+  SimSubresourceRequest image(kImageUrl, "image/gif");
+  SimSubresourceRequest ad_script(kAdScriptUrl, "text/javascript");
+
+  main_resource_->Complete("<body></body><script src=ad_script.js></script>");
+
+  ad_script.Complete(R"SCRIPT(
+    Promise.resolve().then( () => {
+      return Promise.resolve();
+    }).then( () => {
+      image = document.createElement("img");
+      image.src = "image.gif";
+      document.body.appendChild(image);
+    });
+    )SCRIPT");
+
+  ad_tracker_->WaitForSubresource(kImageUrl);
+
+  // Put the gif bytes in a Vector to avoid difficulty with
+  // non null-terminated char*.
+  Vector<char> gif;
+  gif.AppendSpan(base::span(kSmallGifData));
+
+  image.Complete(gif);
+
+  EXPECT_TRUE(
+      IsKnownAdScript(GetDocument().GetExecutionContext(), kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kImageUrl));
+}
+
+TEST_F(AdTrackerSimTest, BrokenPromiseScript) {
+  const char kAdScriptUrl[] = "https://example.com/ad_script.js";
+  const char kVanillaScriptUrl[] = "https://example.com/vanilla_script.js";
+
+  const char kImageUrl[] = "https://example.com/image.gif";
+  SimSubresourceRequest image(kImageUrl, "image/gif");
+  SimSubresourceRequest ad_script(kAdScriptUrl, "text/javascript");
+  SimSubresourceRequest vanilla_script(kVanillaScriptUrl, "text/javascript");
+
+  main_resource_->Complete(R"HTML(
+    <body>
+      <script src='ad_script.js'></script>
+      <script src='vanilla_script.js'></script>
+    </body>
+  )HTML");
+
+  // Run some ad script that fails in the midst of execution. This should
+  // properly clean up in the AdTracker (e.g., the PromiseHook should send a
+  // kAfter) so that the AdTracker doesn't think everything thereafter is ad
+  // related.
+  ad_script.Complete(R"SCRIPT(
+    Promise.resolve().then( () => {
+      asjhdklasjdh();  // this causes an exception
+      return Promise.resolve();
+    });
+    )SCRIPT");
+
+  vanilla_script.Complete(R"SCRIPT(
+    image = document.createElement("img");
+    image.src = "image.gif";
+    document.body.appendChild(image);
+    )SCRIPT");
+
+  ad_tracker_->WaitForSubresource(kImageUrl);
+
+  // Put the gif bytes in a Vector to avoid difficulty with
+  // non null-terminated char*.
+  Vector<char> gif;
+  gif.AppendSpan(base::span(kSmallGifData));
+
+  image.Complete(gif);
+
+  EXPECT_TRUE(
+      IsKnownAdScript(GetDocument().GetExecutionContext(), kAdScriptUrl));
+  EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kAdScriptUrl));
+  EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(kVanillaScriptUrl));
+
+  EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(kImageUrl));
+}
+
+TEST_F(AdTrackerSimTest, VanillaPromiseNotDetected) {
+  const char kVanillaScriptUrl[] = "https://example.com/vanilla_script.js";
+  const char kImageUrl[] = "https://example.com/image.gif";
+  SimSubresourceRequest image(kImageUrl, "image/gif");
+  SimSubresourceRequest vanilla_script(kVanillaScriptUrl, "text/javascript");
+
+  main_resource_->Complete(
+      "<body></body><script src=vanilla_script.js></script>");
+
+  vanilla_script.Complete(R"SCRIPT(
+    Promise.resolve('Promise.resolve').then( () => {
+      image = document.createElement("img");
+      image.src = "image.gif";
+      document.body.appendChild(image);
+    });
+    )SCRIPT");
+
+  ad_tracker_->WaitForSubresource(kImageUrl);
+
+  // Put the gif bytes in a Vector to avoid difficulty with
+  // non null-terminated char*.
+  Vector<char> gif;
+  gif.AppendSpan(base::span(kSmallGifData));
+
+  image.Complete(gif);
+
+  EXPECT_FALSE(
+      IsKnownAdScript(GetDocument().GetExecutionContext(), kVanillaScriptUrl));
+  EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(kVanillaScriptUrl));
+  EXPECT_FALSE(ad_tracker_->RequestWithUrlTaggedAsAd(kImageUrl));
+}
+
 // Image loaded by ad script is tagged as ad.
 TEST_F(AdTrackerSimTest, DataURLImageLoadedWhileExecutingAdScriptAsyncEnabled) {
   // Reset the AdTracker so that it gets the latest base::Feature value on
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 fb4ed4f9..41b7aa3 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
@@ -254,10 +254,10 @@
     for (const Attribute& attr : element->Attributes()) {
       const AtomicString& name = attr.LocalName();
       const AtomicString& value = attr.Value();
-      if (name.FindIgnoringASCIICase(kScriptString) != WTF::kNotFound ||
-          name.FindIgnoringASCIICase(kStyleString) != WTF::kNotFound ||
-          value.FindIgnoringASCIICase(kScriptString) != WTF::kNotFound ||
-          value.FindIgnoringASCIICase(kStyleString) != WTF::kNotFound) {
+      if (name.FindIgnoringASCIICase(kScriptString) != kNotFound ||
+          name.FindIgnoringASCIICase(kStyleString) != kNotFound ||
+          value.FindIgnoringASCIICase(kScriptString) != kNotFound ||
+          value.FindIgnoringASCIICase(kStyleString) != kNotFound) {
         nonceable = false;
         break;
       }
diff --git a/third_party/blink/renderer/core/frame/deprecation/deprecation.json5 b/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
index b548c72..6a5a057 100644
--- a/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
+++ b/third_party/blink/renderer/core/frame/deprecation/deprecation.json5
@@ -228,16 +228,6 @@
       ],
     },
     {
-      name: "H1UserAgentFontSizeInSection",
-      message: "Found an `&lt;h1&gt;` tag within an `&lt;article&gt;`, `&lt;aside&gt;`, `&lt;nav&gt;`, or `&lt;section&gt;` which does not have a specified font-size. The size of this heading text will be changing in this browser in the near future. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements#specifying_a_uniform_font_size_for_h1 for more information.",
-      translation_note: "This warning occurs when a site uses <h1> inside <article>, <aside>, <nav>, or <section>. It means the behavior (font size) may change in a future Chrome release, when some special rules are removed from the browser.",
-      web_features: [
-        "kH1UserAgentFontSizeInSectionApplied",
-      ],
-      chrome_status_feature: 6192419898654720,
-      milestone: 136,
-    },
-    {
       name: "HostCandidateAttributeGetter",
       message: "`RTCPeerConnectionIceErrorEvent.hostCandidate` is deprecated. Please use `RTCPeerConnectionIceErrorEvent.address` or `RTCPeerConnectionIceErrorEvent.port` instead.",
       translation_note: "A deprecation warning shown to developers in the DevTools Issues tab when code tries to use the deprecated hostCandidate field, guiding developers to use the equivalent information in the .address and .port fields instead.",
diff --git a/third_party/blink/renderer/core/frame/local_dom_window_test.cc b/third_party/blink/renderer/core/frame/local_dom_window_test.cc
index aabf1ff..e43b809 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window_test.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window_test.cc
@@ -316,7 +316,7 @@
   window->AddConsoleMessageImpl(console_message, false);
   auto* message_storage = &GetFrame().GetPage()->GetConsoleMessageStorage();
   EXPECT_EQ(1u, message_storage->size());
-  for (WTF::wtf_size_t i = 0; i < message_storage->size(); ++i) {
+  for (wtf_size_t i = 0; i < message_storage->size(); ++i) {
     EXPECT_EQ(mojom::blink::ConsoleMessageCategory::Cors,
               *message_storage->at(i)->Category());
   }
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 17d2181..36baf908 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -43,7 +43,6 @@
 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
 #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
 #include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/common/subresource_load_metrics.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
@@ -63,6 +62,7 @@
 #include "third_party/blink/public/web/web_history_commit_type.h"
 #include "third_party/blink/public/web/web_manifest_manager.h"
 #include "third_party/blink/public/web/web_navigation_params.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/icon_url.h"
 #include "third_party/blink/renderer/core/frame/frame_client.h"
@@ -243,7 +243,8 @@
   virtual void DidObserveNewFeatureUsage(const UseCounterFeature&) {}
 
   // A new soft navigation was observed.
-  virtual void DidObserveSoftNavigation(SoftNavigationMetrics metrics) {}
+  virtual void DidObserveSoftNavigation(
+      SoftNavigationMetricsForReporting metrics) {}
 
   // Reports that visible elements in the frame shifted (bit.ly/lsm-explainer).
   virtual void DidObserveLayoutShift(double score, bool after_input_or_scroll) {
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 477ddbe..22f1a4a 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -871,7 +871,7 @@
 
 // A new soft navigation was observed.
 void LocalFrameClientImpl::DidObserveSoftNavigation(
-    SoftNavigationMetrics metrics) {
+    SoftNavigationMetricsForReporting metrics) {
   if (WebLocalFrameClient* client = web_frame_->Client()) {
     client->DidObserveSoftNavigation(metrics);
   }
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index c1f8fc07..081c8fab 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -41,7 +41,6 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/cpp/permissions_policy/permissions_policy_declaration.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/common/subresource_load_metrics.h"
 #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -171,7 +170,8 @@
   void DidObserveSubresourceLoad(
       const SubresourceLoadMetrics& subresource_load_metrics) override;
   void DidObserveNewFeatureUsage(const UseCounterFeature&) override;
-  void DidObserveSoftNavigation(SoftNavigationMetrics metrics) override;
+  void DidObserveSoftNavigation(
+      SoftNavigationMetricsForReporting metrics) override;
   void DidObserveLayoutShift(double score, bool after_input_or_scroll) override;
   void SelectorMatchChanged(const Vector<String>& added_selectors,
                             const Vector<String>& removed_selectors) override;
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
index b6673d7..3d6d330 100644
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
@@ -1016,8 +1016,8 @@
   ui::mojom::blink::AttributedStringPtr attributed_string = nullptr;
   base::apple::ScopedCFTypeRef<CFAttributedStringRef> string =
       SubstringUtil::AttributedSubstringInRange(
-          frame_, base::checked_cast<WTF::wtf_size_t>(range.start()),
-          base::checked_cast<WTF::wtf_size_t>(range.length()), baseline_point);
+          frame_, base::checked_cast<wtf_size_t>(range.start()),
+          base::checked_cast<wtf_size_t>(range.length()), baseline_point);
   if (string) {
     attributed_string = ui::mojom::blink::AttributedString::From(string.get());
   }
diff --git a/third_party/blink/renderer/core/frame/use_counter_impl_test.cc b/third_party/blink/renderer/core/frame/use_counter_impl_test.cc
index 75b358b..8b08e9e2 100644
--- a/third_party/blink/renderer/core/frame/use_counter_impl_test.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_impl_test.cc
@@ -723,33 +723,4 @@
   }
 }
 
-TEST_F(UseCounterImplTest, H1UserAgentFontSizeInSectionApplied) {
-  auto dummy_page_holder =
-      std::make_unique<DummyPageHolder>(gfx::Size(800, 600));
-  Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
-  Document& document = dummy_page_holder->GetDocument();
-  WebFeature feature = WebFeature::kH1UserAgentFontSizeInSectionApplied;
-
-  EXPECT_FALSE(document.IsUseCounted(feature));
-
-  document.documentElement()->SetInnerHTMLWithoutTrustedTypes("<h1></h1>");
-  UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(document.IsUseCounted(feature))
-      << "Not inside sectioning element";
-
-  document.documentElement()->SetInnerHTMLWithoutTrustedTypes(R"HTML(
-      <article><h1 style="font-size: 10px"></h1></article>
-  )HTML");
-  UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(document.IsUseCounted(feature))
-      << "Inside sectioning element with author font-size";
-
-  document.documentElement()->SetInnerHTMLWithoutTrustedTypes(R"HTML(
-      <article><h1></h1></article>
-  )HTML");
-  UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(document.IsUseCounted(feature))
-      << "Inside sectioning element with UA font-size";
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index 1f39f19..cb9e5ad 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -283,6 +283,9 @@
   virtual String GetIdFromControl(const Element* element) { return String(); }
   virtual int LayerCount() const { return 0; }
   virtual bool IsCanvas2DResourceValid() { NOTREACHED(); }
+  virtual CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() {
+    NOTREACHED();
+  }
   // If the ResourceProvider currently exists, replaces it with a newly-created
   // CanvasResourceProvider.
   virtual void DropAndRecreateExistingCanvas2DResourceProvider() {
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index fb71a1b..6a12ad9 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -373,7 +373,7 @@
     return false;
   }
 
-  if (!RenderingContext()->IsCanvas2DResourceValid()) {
+  if (!RenderingContext()->GetOrCreateCanvas2DResourceProvider()) {
     return false;
   }
 
@@ -1893,25 +1893,13 @@
                                                 bool image_is_texture_backed) {
   CHECK(IsRenderingContext2D());
 
-  // For images coming from WebGL/WebGPU/Canvas2D canvases, use the image
-  // itself as the source of truth for whether the canvas is accelerated. For
-  // WebGL/WebGPU it's more accurate than IsAccelerated(), and for canvas2D
-  // it's effectively the same check.
-  // TODO(crbug.com/352263194): Do this universally when the source is a
-  // canvas, as it's more accurate for all context types than using
-  // source->IsAccelerated().
-  bool source_is_webgl_or_webgpu_or_canvas2d = false;
-  if (source->IsCanvasElement() || source->IsOffscreenCanvas()) {
-    auto* source_as_host = static_cast<CanvasRenderingContextHost*>(source);
-    source_is_webgl_or_webgpu_or_canvas2d =
-        source_as_host->IsWebGL() || source_as_host->IsWebGPU() ||
-        source_as_host->IsRenderingContext2D();
-  }
-
-  bool source_is_accelerated = source_is_webgl_or_webgpu_or_canvas2d
-                                   ? image_is_texture_backed
-                                   : source->IsAccelerated();
-
+  // For images coming from canvases, use the image itself as the source of
+  // truth for whether the canvas is accelerated, as
+  // CanvasRenderingContextHost::IsAccelerated() is canvas2d-specific.
+  bool source_is_accelerated =
+      (source->IsCanvasElement() || source->IsOffscreenCanvas())
+          ? image_is_texture_backed
+          : source->IsAccelerated();
   // If the source is GPU-accelerated, and the canvas is not, but could be...
   if (source_is_accelerated && ShouldAccelerate() &&
       GetRasterModeForCanvas2D() == RasterMode::kCPU) {
diff --git a/third_party/blink/renderer/core/html/custom/custom_state_set.cc b/third_party/blink/renderer/core/html/custom/custom_state_set.cc
index 6545baf..477a08f 100644
--- a/third_party/blink/renderer/core/html/custom/custom_state_set.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_state_set.cc
@@ -70,8 +70,9 @@
                                       const String& value,
                                       ExceptionState&) {
   wtf_size_t index = list_.Find(value);
-  if (index == WTF::kNotFound)
+  if (index == kNotFound) {
     return false;
+  }
   list_.EraseAt(index);
   for (auto& iterator : iterators_)
     iterator->DidEraseAt(index);
diff --git a/third_party/blink/renderer/core/html/fenced_frame/document_fenced_frames.cc b/third_party/blink/renderer/core/html/fenced_frame/document_fenced_frames.cc
index bddd588..a335168 100644
--- a/third_party/blink/renderer/core/html/fenced_frame/document_fenced_frames.cc
+++ b/third_party/blink/renderer/core/html/fenced_frame/document_fenced_frames.cc
@@ -49,7 +49,7 @@
 void DocumentFencedFrames::DeregisterFencedFrame(
     HTMLFencedFrameElement* fenced_frame) {
   wtf_size_t index = fenced_frames_.Find(fenced_frame);
-  if (index != WTF::kNotFound) {
+  if (index != kNotFound) {
     fenced_frames_.EraseAt(index);
   }
 
diff --git a/third_party/blink/renderer/core/html/forms/text_control_element.cc b/third_party/blink/renderer/core/html/forms/text_control_element.cc
index b7efa99..e3c3278c 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_element.cc
@@ -1015,7 +1015,7 @@
   wtf_size_t start = 0;
   while (start < value.length()) {
     wtf_size_t i = value.find('\n', start);
-    if (i == WTF::kNotFound) {
+    if (i == kNotFound) {
       AppendText(value, start, value.length(), container);
       break;
     }
diff --git a/third_party/blink/renderer/core/html/html_template_element.cc b/third_party/blink/renderer/core/html/html_template_element.cc
index c8044ff..bb118abf 100644
--- a/third_party/blink/renderer/core/html/html_template_element.cc
+++ b/third_party/blink/renderer/core/html/html_template_element.cc
@@ -88,7 +88,8 @@
 
 void HTMLTemplateElement::BeginPatch(ContainerNode& target) {
   SetOverrideInsertionTarget(target);
-  patch_status_ = DOMPatchStatus::Start(*this, target);
+  patch_status_ = DOMPatchStatus::Create(target, this);
+  patch_status_->Start();
 }
 
 void HTMLTemplateElement::FinishParsingChildren() {
diff --git a/third_party/blink/renderer/core/html/parser/literal_buffer.h b/third_party/blink/renderer/core/html/parser/literal_buffer.h
index fc2d649..c48bd10 100644
--- a/third_party/blink/renderer/core/html/parser/literal_buffer.h
+++ b/third_party/blink/renderer/core/html/parser/literal_buffer.h
@@ -34,7 +34,7 @@
 // it avoids unnecessary register spills. See https://crbug.com/1205338.
 // Use one of the concrete implementations: LCharLiteralBuffer or
 // UCharLiteralBuffer.
-template <typename T, wtf_size_t kInlineSize>
+template <typename T, blink::wtf_size_t kInlineSize>
 class LiteralBufferBase {
   static_assert(std::is_same<LChar, T>::value || std::is_same<UChar, T>::value,
                 "T must be a character type");
@@ -48,8 +48,8 @@
   }
 
   ALWAYS_INLINE const T* data() const { return begin_; }
-  ALWAYS_INLINE wtf_size_t size() const {
-    return base::checked_cast<wtf_size_t>(end_ - begin_);
+  ALWAYS_INLINE blink::wtf_size_t size() const {
+    return base::checked_cast<blink::wtf_size_t>(end_ - begin_);
   }
 
   // Iterators, so this type meets the requirements of
@@ -63,7 +63,7 @@
 
   ALWAYS_INLINE bool IsEmpty() const { return begin_ == end_; }
 
-  ALWAYS_INLINE const T& operator[](wtf_size_t index) const {
+  ALWAYS_INLINE const T& operator[](blink::wtf_size_t index) const {
     CHECK_GT(size(), index);
     // SAFETY: Check above.
     return UNSAFE_BUFFERS(begin_[index]);
@@ -82,7 +82,7 @@
     UNSAFE_TODO(*end_++) = val;
   }
 
-  template <typename OtherT, wtf_size_t kOtherSize>
+  template <typename OtherT, blink::wtf_size_t kOtherSize>
   void AppendLiteralImpl(const LiteralBufferBase<OtherT, kOtherSize>& val) {
     static_assert(sizeof(T) >= sizeof(OtherT),
                   "T is not big enough to contain OtherT");
@@ -94,9 +94,9 @@
     UNSAFE_TODO(end_ += count);
   }
 
-  template <wtf_size_t kOtherInlineSize>
+  template <blink::wtf_size_t kOtherInlineSize>
   void Copy(const LiteralBufferBase<T, kOtherInlineSize>& other) {
-    wtf_size_t other_size = other.size();
+    blink::wtf_size_t other_size = other.size();
     if (capacity() < other_size) {
       // Create large-enough heap-allocated storage.
       if (!is_stored_inline())
@@ -123,7 +123,7 @@
           UNSAFE_TODO(other.begin_ + BUFFER_INLINE_CAPACITY);
     } else {
       DCHECK_GE(capacity(), other.size());  // Sanity check.
-      wtf_size_t other_size = other.size();
+      blink::wtf_size_t other_size = other.size();
       std::copy_n(other.data(), other_size, begin_);
       end_ = UNSAFE_TODO(begin_ + other_size);
     }
@@ -181,7 +181,7 @@
   T inline_storage[BUFFER_INLINE_CAPACITY];
 };
 
-template <wtf_size_t kInlineSize>
+template <blink::wtf_size_t kInlineSize>
 class LCharLiteralBuffer : public LiteralBufferBase<LChar, kInlineSize> {
  public:
   LCharLiteralBuffer() = default;
@@ -190,7 +190,7 @@
 
   ~LCharLiteralBuffer() = default;
 
-  template <wtf_size_t kOtherInlineSize>
+  template <blink::wtf_size_t kOtherInlineSize>
   LCharLiteralBuffer& operator=(
       const LCharLiteralBuffer<kOtherInlineSize>& other) {
     if (this->data() != other.data())
@@ -212,7 +212,7 @@
   blink::String AsString() const { return blink::String(*this); }
 };
 
-template <wtf_size_t kInlineSize>
+template <blink::wtf_size_t kInlineSize>
 class UCharLiteralBuffer : public LiteralBufferBase<UChar, kInlineSize> {
  public:
   UCharLiteralBuffer() = default;
@@ -221,7 +221,7 @@
 
   ~UCharLiteralBuffer() = default;
 
-  template <wtf_size_t kOtherInlineSize>
+  template <blink::wtf_size_t kOtherInlineSize>
   UCharLiteralBuffer& operator=(
       const UCharLiteralBuffer<kOtherInlineSize>& other) {
     if (this->data() == other.data())
@@ -259,7 +259,7 @@
     bitwise_or_all_chars_ |= val;
   }
 
-  template <wtf_size_t kOtherSize>
+  template <blink::wtf_size_t kOtherSize>
   void AppendLiteral(const LCharLiteralBuffer<kOtherSize>& val) {
     this->AppendLiteralImpl(val);
   }
@@ -283,7 +283,7 @@
 
  private:
   // Needed for operator=.
-  template <wtf_size_t kOtherInlineSize>
+  template <blink::wtf_size_t kOtherInlineSize>
   friend class UCharLiteralBuffer;
 
   // Bitwise OR of all characters in our buffer. We actually
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css
index 6304f3b..a14fbce 100644
--- a/third_party/blink/renderer/core/html/resources/html.css
+++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -175,34 +175,36 @@
     font-weight: bold
 }
 
-:-webkit-any(article,aside,nav,section) h1 {
-    font-size: 1.5em;
-    margin-block-start: 0.83__qem;
-    margin-block-end: 0.83em;
-}
+@supports blink-feature(SpecialRulesForNestedH1Elements) {
+  :-webkit-any(article,aside,nav,section) h1 {
+      font-size: 1.5em;
+      margin-block-start: 0.83__qem;
+      margin-block-end: 0.83em;
+  }
 
-:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
-    font-size: 1.17em;
-    margin-block-start: 1__qem;
-    margin-block-end: 1em;
-}
+  :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
+      font-size: 1.17em;
+      margin-block-start: 1__qem;
+      margin-block-end: 1em;
+  }
 
-:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
-    font-size: 1.00em;
-    margin-block-start: 1.33__qem;
-    margin-block-end: 1.33em;
-}
+  :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
+      font-size: 1.00em;
+      margin-block-start: 1.33__qem;
+      margin-block-end: 1.33em;
+  }
 
-:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
-    font-size: .83em;
-    margin-block-start: 1.67__qem;
-    margin-block-end: 1.67em;
-}
+  :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
+      font-size: .83em;
+      margin-block-start: 1.67__qem;
+      margin-block-end: 1.67em;
+  }
 
-:-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
-    font-size: .67em;
-    margin-block-start: 2.33__qem;
-    margin-block-end: 2.33em;
+  :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) :-webkit-any(article,aside,nav,section) h1 {
+      font-size: .67em;
+      margin-block-start: 2.33__qem;
+      margin-block-end: 2.33em;
+  }
 }
 
 h2 {
diff --git a/third_party/blink/renderer/core/inspector/dom_editor.cc b/third_party/blink/renderer/core/inspector/dom_editor.cc
index dff7fa1..7c26d75f 100644
--- a/third_party/blink/renderer/core/inspector/dom_editor.cc
+++ b/third_party/blink/renderer/core/inspector/dom_editor.cc
@@ -55,6 +55,9 @@
   RemoveChildAction& operator=(const RemoveChildAction&) = delete;
 
   bool Perform(ExceptionState& exception_state) override {
+    if (!parent_node_) {
+      return false;
+    }
     anchor_node_ = node_->nextSibling();
     return Redo(exception_state);
   }
@@ -288,6 +291,9 @@
   ReplaceChildNodeAction& operator=(const ReplaceChildNodeAction&) = delete;
 
   bool Perform(ExceptionState& exception_state) override {
+    if (!parent_node_) {
+      return false;
+    }
     return Redo(exception_state);
   }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_event_breakpoints_agent.cc b/third_party/blink/renderer/core/inspector/inspector_event_breakpoints_agent.cc
index d688868..b669a1d 100644
--- a/third_party/blink/renderer/core/inspector/inspector_event_breakpoints_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_event_breakpoints_agent.cc
@@ -68,7 +68,7 @@
 
 void InspectorEventBreakpointsAgent::DidFireWebGLErrorOrWarning(
     const String& message) {
-  if (message.FindIgnoringASCIICase("error") != WTF::kNotFound) {
+  if (message.FindIgnoringASCIICase("error") != kNotFound) {
     DidFireWebGLError(String());
   } else {
     DidFireWebGLWarning();
diff --git a/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc b/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc
index 3cc24ad..89a6184 100644
--- a/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_ghost_rules.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_counted_set.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/layout/block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/block_layout_algorithm.cc
index 2445f94..0ae81458 100644
--- a/third_party/blink/renderer/core/layout/block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/block_layout_algorithm.cc
@@ -348,13 +348,16 @@
   if (relayout_type == kRelayoutIgnoringLineClamp) {
     line_clamp_data_.data.state = LineClampData::kDisabled;
     line_clamp_data_.ignore_line_clamp = true;
-  } else if (relayout_type == kRelayoutWithLineClampBlockSize) {
+  } else if (relayout_type == kRelayoutClampingByLines) {
     line_clamp_data_.data.state = LineClampData::kClampByLines;
     line_clamp_data_.data.lines_until_clamp =
         line_clamp_data_.initial_lines_until_clamp =
             previous.line_clamp_data_.data.lines_until_clamp;
-  } else if (previous.line_clamp_data_.data.state ==
-             LineClampData::kClampByLines) {
+  } else if (relayout_type == kRelayoutClampingAfterLayoutObject) {
+    line_clamp_data_.data.state = LineClampData::kClampAfterLayoutObject;
+    line_clamp_data_.data.clamp_after_layout_object =
+        previous.line_clamp_data_.last_layout_object;
+  } else if (previous.line_clamp_data_.data.IsClampByLines()) {
     line_clamp_data_.data.state = LineClampData::kClampByLines;
     line_clamp_data_.data.lines_until_clamp =
         line_clamp_data_.initial_lines_until_clamp =
@@ -618,11 +621,27 @@
           *result->GetEarlyBreak());
     }
     case LayoutResult::kNeedsLineClampRelayout:
-      if (line_clamp_data_.data.state == LineClampData::kClampByLines) {
+      if (!line_clamp_data_.data.IsMeasureUntilBfcOffset()) {
+        DCHECK(line_clamp_data_.data.IsClampByLines());
+        DCHECK_EQ(result->LinesUntilClamp(), 0);
         return RelayoutIgnoringLineClamp();
       }
       if (GetConstraintSpace().IsNewFormattingContext()) {
-        return RelayoutWithLineClampBlockSize(result->LinesUntilClamp());
+        if (result->LineClampAfterLayoutObject()) {
+          return RelayoutClampingAfterLayoutObject(
+              result->LineClampAfterLayoutObject());
+        }
+        int lines_to_relayout;
+        if (!line_clamp_data_.data.IsClampByLines()) {
+          lines_to_relayout = result->LinesUntilClamp();
+        } else {
+          // If we're clamping by both lines and height, result->LinesUntilClamp
+          // is the last line number before clamp, counting down from
+          // Style().LineClamp().
+          DCHECK_GT(Style().LineClamp(), 0);
+          lines_to_relayout = Style().LineClamp() - result->LinesUntilClamp();
+        }
+        return RelayoutClampingByLines(lines_to_relayout);
       }
       // Propagate the error upwards until we reach the BFC root.
       return result;
@@ -669,16 +688,24 @@
 }
 
 NOINLINE const LayoutResult* BlockLayoutAlgorithm::RelayoutIgnoringLineClamp() {
-  DCHECK_EQ(line_clamp_data_.data.state, LineClampData::kClampByLines);
+  DCHECK(line_clamp_data_.data.IsClampByLines());
   return Relayout<BlockLayoutAlgorithm>(kRelayoutIgnoringLineClamp);
 }
 
+NOINLINE const LayoutResult* BlockLayoutAlgorithm::RelayoutClampingByLines(
+    int lines_until_clamp) {
+  DCHECK(line_clamp_data_.data.IsMeasureUntilBfcOffset());
+  line_clamp_data_.data.lines_until_clamp = std::max(0, lines_until_clamp);
+  return Relayout<BlockLayoutAlgorithm>(kRelayoutClampingByLines);
+}
+
 NOINLINE const LayoutResult*
-BlockLayoutAlgorithm::RelayoutWithLineClampBlockSize(int lines_until_clamp) {
-  DCHECK_EQ(line_clamp_data_.data.state,
-            LineClampData::kMeasureLinesUntilBfcOffset);
-  line_clamp_data_.data.lines_until_clamp = std::max(1, lines_until_clamp);
-  return Relayout<BlockLayoutAlgorithm>(kRelayoutWithLineClampBlockSize);
+BlockLayoutAlgorithm::RelayoutClampingAfterLayoutObject(
+    const LayoutObject* layout_object) {
+  DCHECK(line_clamp_data_.data.IsMeasureUntilBfcOffset());
+  DCHECK(layout_object);
+  line_clamp_data_.last_layout_object = layout_object;
+  return Relayout<BlockLayoutAlgorithm>(kRelayoutClampingAfterLayoutObject);
 }
 
 NOINLINE const LayoutResult* BlockLayoutAlgorithm::RelayoutForTextBoxTrimEnd() {
@@ -723,7 +750,7 @@
     abort_when_bfc_block_offset_updated_ = true;
   }
 
-  if (Style().HasAutoLineClamp()) {
+  if (Style().HasLineClamp()) {
     if (!line_clamp_data_.data.IsLineClampContext()) {
       LayoutUnit clamp_bfc_offset = ChildAvailableSize().block_size;
       if (clamp_bfc_offset == kIndefiniteSize) {
@@ -739,12 +766,7 @@
             (BorderScrollbarPadding().block_start + clamp_bfc_offset)
                 .ClampNegativeToZero();
       }
-      line_clamp_data_.UpdateClampOffsetFromStyle(
-          clamp_bfc_offset, BorderScrollbarPadding().block_start);
-    }
-  } else if (Style().HasLineClamp()) {
-    if (!line_clamp_data_.data.IsLineClampContext()) {
-      line_clamp_data_.UpdateLinesFromStyle(Style().LineClamp());
+      line_clamp_data_.UpdateFromStyle(Style().LineClamp(), clamp_bfc_offset);
     }
   } else {
     if (Style().WebkitLineClamp() != 0) {
@@ -755,8 +777,7 @@
     // If we're clamping by BFC offset, we need to subtract the bottom bmp to
     // leave room for it. This doesn't apply if we're relaying out to fix the
     // offset, because that already accounts for the bmp.
-    if (line_clamp_data_.data.state ==
-        LineClampData::kMeasureLinesUntilBfcOffset) {
+    if (line_clamp_data_.data.IsMeasureUntilBfcOffset()) {
       MarginStrut end_margin_strut = constraint_space.LineClampEndMarginStrut();
       end_margin_strut.Append(
           ComputeMarginsForSelf(constraint_space, Style()).block_end,
@@ -858,6 +879,15 @@
   }
 #endif
 
+  // Clamping at the start of a line-clamp container.
+  // This can only happen when clamping by a height (e.g. line-clamp: auto;
+  // max-height: 0).
+  if (constraint_space.IsNewFormattingContext() &&
+      line_clamp_data_.IsPastClampPoint()) {
+    line_clamp_data_.previous_inflow_position_when_clamped =
+        previous_inflow_position;
+  }
+
   // If this node is a quirky container, (we are in quirks mode and either a
   // table cell or body), we set our margin strut to a mode where it only
   // considers non-quirky margins. E.g.
@@ -1374,6 +1404,8 @@
   } else {
     container_builder_.SetLinesUntilClamp(
         line_clamp_data_.data.LinesUntilClamp(/*show_measured_lines*/ true));
+    container_builder_.SetLineClampAfterLayoutObject(
+        line_clamp_data_.last_layout_object);
   }
 
   if (constraint_space.UseFirstLineStyle()) {
@@ -1446,10 +1478,9 @@
   DCHECK_GT(result.line_count, 0u);
   if (max_lines) {
     DCHECK(result.line_count <= max_lines);
-    DCHECK_EQ(line_clamp_data_.data.state, LineClampData::kClampByLines);
+    DCHECK(line_clamp_data_.data.IsClampByLines());
     line_clamp_data_.data.lines_until_clamp -= result.line_count;
-  } else if (line_clamp_data_.data.state ==
-             LineClampData::kMeasureLinesUntilBfcOffset) {
+  } else if (line_clamp_data_.data.IsMeasureUntilBfcOffset()) {
     line_clamp_data_.data.lines_until_clamp += result.line_count;
   }
 
@@ -1871,6 +1902,8 @@
           *previous_inflow_position, Padding().block_end)) {
     container_builder_.SetLinesUntilClamp(
         line_clamp_data_.LinesUntilClamp(/*show_measured_lines*/ true));
+    container_builder_.SetLineClampAfterLayoutObject(
+        line_clamp_data_.last_layout_object);
     return LayoutResult::kNeedsLineClampRelayout;
   }
 
@@ -2204,9 +2237,10 @@
   // HandleNonSuccessfulLayoutResult, it needs to be propagated upwards until
   // the BFC root.
   if (layout_result->Status() == LayoutResult::kNeedsLineClampRelayout) {
-    DCHECK_EQ(line_clamp_data_.data.state,
-              LineClampData::kMeasureLinesUntilBfcOffset);
+    DCHECK(line_clamp_data_.data.IsMeasureUntilBfcOffset());
     container_builder_.SetLinesUntilClamp(layout_result->LinesUntilClamp());
+    container_builder_.SetLineClampAfterLayoutObject(
+        line_clamp_data_.PropagateClampAfterLayoutObject(layout_result));
     return LayoutResult::kNeedsLineClampRelayout;
   }
 
@@ -2409,9 +2443,10 @@
     // HandleNonSuccessfulLayoutResult, it needs to be propagated upwards until
     // the BFC root.
     if (layout_result->Status() == LayoutResult::kNeedsLineClampRelayout) {
-      DCHECK_EQ(line_clamp_data_.data.state,
-                LineClampData::kMeasureLinesUntilBfcOffset);
+      DCHECK(line_clamp_data_.data.IsMeasureUntilBfcOffset());
       container_builder_.SetLinesUntilClamp(layout_result->LinesUntilClamp());
+      container_builder_.SetLineClampAfterLayoutObject(
+          line_clamp_data_.PropagateClampAfterLayoutObject(layout_result));
       return LayoutResult::kNeedsLineClampRelayout;
     }
 
@@ -2586,6 +2621,8 @@
                                             Padding().block_end)) {
       container_builder_.SetLinesUntilClamp(
           line_clamp_data_.LinesUntilClamp(/*show_measured_lines*/ true));
+      container_builder_.SetLineClampAfterLayoutObject(
+          line_clamp_data_.last_layout_object);
       return LayoutResult::kNeedsLineClampRelayout;
     }
   }
@@ -2621,8 +2658,7 @@
     }
   }
   if (container_builder_.ShouldTextBoxTrimNodeEnd()) {
-    if (line_clamp_data_.data.state ==
-            LineClampData::kMeasureLinesUntilBfcOffset &&
+    if (line_clamp_data_.data.IsMeasureUntilBfcOffset() &&
         layout_result->TrimBlockEndBy() &&
         layout_result->GetPhysicalFragment().GetBreakToken()) {
       // If we trimmed the end only because we're in the first layout of a
@@ -3829,4 +3865,127 @@
   return {logical_offset.inline_offset + offset, logical_offset.block_offset};
 }
 
+void BlockLineClampData::UpdateFromStyle(int lines_until_clamp,
+                                         LayoutUnit clamp_bfc_offset) {
+  if (ignore_line_clamp) {
+    DCHECK_EQ(data.state, LineClampData::kDisabled);
+    return;
+  }
+
+  DCHECK_EQ(data.state, LineClampData::kDisabled);
+  DCHECK_GE(lines_until_clamp, 0);
+  if (!lines_until_clamp) {
+    if (clamp_bfc_offset == kIndefiniteSize) {
+      data.state = LineClampData::kDisabled;
+    } else {
+      data.state = LineClampData::kMeasureLinesUntilBfcOffset;
+      data.lines_until_clamp = 0;
+      data.clamp_bfc_offset = clamp_bfc_offset;
+    }
+  } else {
+    if (clamp_bfc_offset == kIndefiniteSize) {
+      data.state = LineClampData::kClampByLines;
+      data.lines_until_clamp = lines_until_clamp;
+    } else {
+      data.state = LineClampData::kClampByLinesWithBfcOffset;
+      data.lines_until_clamp = lines_until_clamp;
+      data.clamp_bfc_offset = clamp_bfc_offset;
+    }
+  }
+}
+
+bool BlockLineClampData::UpdateAfterLayout(
+    const LayoutResult* layout_result,
+    LayoutUnit bfc_block_offset,
+    const PreviousInflowPosition& previous_inflow_position,
+    LayoutUnit block_end_padding) {
+  const PhysicalFragment& fragment = layout_result->GetPhysicalFragment();
+
+  int old_lines_until_clamp = 0;
+  if (data.IsClampByLines() || data.IsMeasureUntilBfcOffset()) {
+    old_lines_until_clamp = data.lines_until_clamp;
+    if (!fragment.IsFormattingContextRoot() && !ignore_further_lines) {
+      data.lines_until_clamp = layout_result->LinesUntilClamp();
+    }
+  }
+
+  if (data.IsMeasureUntilBfcOffset() &&
+      !previous_inflow_position_when_clamped.has_value()) {
+    // We compute the margin strut we'd have after this block if we were to
+    // clamp here.
+    MarginStrut collapsed_strut = previous_inflow_position.margin_strut;
+    collapsed_strut.positive_margin = std::max(
+        collapsed_strut.positive_margin, end_margin_strut.positive_margin);
+    collapsed_strut.quirky_positive_margin =
+        std::max(collapsed_strut.quirky_positive_margin,
+                 end_margin_strut.quirky_positive_margin);
+    collapsed_strut.negative_margin = std::max(
+        collapsed_strut.negative_margin, end_margin_strut.negative_margin);
+
+    // The extra space after the current box that would be added by ruby
+    // annotations, considering that the annotations eat into the following
+    // padding if it exists, and that we have already subtracted the block end
+    // padding from the clamp BFC offset.
+    LayoutUnit padding_annotation_overflow;
+    if (previous_inflow_position.block_end_annotation_space < LayoutUnit()) {
+      padding_annotation_overflow =
+          std::max(previous_inflow_position.block_end_annotation_space,
+                   -block_end_padding);
+    }
+
+    LayoutUnit bfc_offset = bfc_block_offset +
+                            previous_inflow_position.logical_block_offset +
+                            padding_annotation_overflow +
+                            (collapsed_strut.Sum() - end_margin_strut.Sum());
+
+    if (bfc_offset > data.clamp_bfc_offset) {
+      data.lines_until_clamp = old_lines_until_clamp;
+      return false;
+    }
+
+    if (old_lines_until_clamp == data.lines_until_clamp ||
+        layout_result->LineClampAfterLayoutObject()) {
+      // Empty line boxes should be ignored, they shouldn't even set
+      // last_layout_object to null. Other fragments shouldn't have a null
+      // layout object.
+      if (!fragment.IsLineBox()) {
+        last_layout_object = fragment.GetLayoutObject();
+        DCHECK(last_layout_object);
+      }
+    } else {
+      last_layout_object = nullptr;
+    }
+  }
+
+  if (data.IsClampByLines()) {
+    if (layout_result->WouldBeLastLineIfNotForEllipsis()) {
+      DCHECK(fragment.IsLineBox());
+      DCHECK_EQ(data.lines_until_clamp, 0);
+      ignore_further_lines = true;
+    }
+
+    if (IsPastClampPoint()) {
+      if (!previous_inflow_position_when_clamped.has_value()) {
+        previous_inflow_position_when_clamped = previous_inflow_position;
+      }
+      // Returning here so we don't run the `IsMeasureUntilBfcOffset` branch.
+      return true;
+    }
+  }
+
+  // With kClampAfterLayoutObject, if we've found the layout object, then we
+  // switch states to kClampByLines with negative lines. If the child layout
+  // result has negative lines, then the layout object was found there.
+  if (data.state == LineClampData::kClampAfterLayoutObject &&
+      (layout_result->LinesUntilClamp() < 0 ||
+       data.clamp_after_layout_object == fragment.GetLayoutObject())) {
+    DCHECK(!previous_inflow_position_when_clamped);
+    data.state = LineClampData::kClampByLines;
+    data.lines_until_clamp = -1;
+    previous_inflow_position_when_clamped = previous_inflow_position;
+  }
+
+  return true;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/block_layout_algorithm.h b/third_party/blink/renderer/core/layout/block_layout_algorithm.h
index 5a16873d..09156b9 100644
--- a/third_party/blink/renderer/core/layout/block_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/block_layout_algorithm.h
@@ -61,11 +61,12 @@
 };
 
 struct BlockLineClampData {
-  DISALLOW_NEW();
+  STACK_ALLOCATED();
 
+ public:
   explicit BlockLineClampData(LineClampData line_clamp_data)
       : data(line_clamp_data) {
-    if (data.state == LineClampData::kClampByLines) {
+    if (data.IsClampByLines()) {
       initial_lines_until_clamp = data.lines_until_clamp;
     }
   }
@@ -82,107 +83,36 @@
     if (!previous_inflow_position_when_clamped.has_value()) {
       return false;
     }
-    DCHECK_EQ(data.state, LineClampData::kClampByLines);
+    DCHECK(data.IsClampByLines());
     return data.lines_until_clamp == 0;
   }
 
-  void UpdateClampOffsetFromStyle(LayoutUnit clamp_bfc_offset,
-                                  LayoutUnit content_edge) {
-    if (ignore_line_clamp) {
-      DCHECK_EQ(data.state, LineClampData::kDisabled);
-      return;
-    }
-
-    if (data.state == LineClampData::kMeasureLinesUntilBfcOffset) {
-      // We're doing relayout with a different BFC offset which we obtained from
-      // the previous layout. This offset must be less than the one we get from
-      // style.
-      DCHECK_LT(data.clamp_bfc_offset, clamp_bfc_offset);
-      return;
-    }
-
-    DCHECK_EQ(data.state, LineClampData::kDisabled);
-    if (clamp_bfc_offset == kIndefiniteSize) {
-      data.state = LineClampData::kDisabled;
-    } else {
-      data.state = LineClampData::kMeasureLinesUntilBfcOffset;
-      data.lines_until_clamp = 0;
-      data.clamp_bfc_offset = clamp_bfc_offset;
-    }
-  }
-
-  void UpdateLinesFromStyle(int lines_until_clamp) {
-    if (ignore_line_clamp) {
-      DCHECK_EQ(data.state, LineClampData::kDisabled);
-      return;
-    }
-
-    DCHECK_EQ(data.state, LineClampData::kDisabled);
-    data.state = LineClampData::kClampByLines;
-    data.lines_until_clamp = lines_until_clamp;
-  }
+  void UpdateFromStyle(int lines_until_clamp, LayoutUnit clamp_bfc_offset);
 
   // Returns false if we need to relayout with a different clamp BFC offset.
   bool UpdateAfterLayout(const LayoutResult* layout_result,
                          LayoutUnit bfc_block_offset,
                          const PreviousInflowPosition& previous_inflow_position,
-                         LayoutUnit block_end_padding) {
-    if (data.state == LineClampData::kClampByLines) {
-      if (!layout_result->GetPhysicalFragment().IsFormattingContextRoot() &&
-          !ignore_further_lines) {
-        data.lines_until_clamp = layout_result->LinesUntilClamp();
+                         LayoutUnit block_end_padding);
 
-        if (layout_result->WouldBeLastLineIfNotForEllipsis()) {
-          DCHECK(layout_result->GetPhysicalFragment().IsLineBox());
-          DCHECK_EQ(data.lines_until_clamp, 0);
-          ignore_further_lines = true;
-        }
-      }
-
-      if (IsPastClampPoint() &&
-          !previous_inflow_position_when_clamped.has_value()) {
-        previous_inflow_position_when_clamped = previous_inflow_position;
-      }
+  // If a child box's layout fails because it overflows, and we're propagating
+  // that failure up until the line-clamp container, this method returns the
+  // "clamp after layout object" value we should propagate upwards.
+  const LayoutObject* PropagateClampAfterLayoutObject(
+      const LayoutResult* layout_result) const {
+    // The child overflew after a lineless box; propagate that layout object.
+    if (layout_result->LineClampAfterLayoutObject()) {
+      return layout_result->LineClampAfterLayoutObject();
     }
-
-    if (data.state == LineClampData::kMeasureLinesUntilBfcOffset) {
-      // We compute the margin strut we'd have after this block if we were to
-      // clamp here.
-      MarginStrut collapsed_strut = previous_inflow_position.margin_strut;
-      collapsed_strut.positive_margin = std::max(
-          collapsed_strut.positive_margin, end_margin_strut.positive_margin);
-      collapsed_strut.quirky_positive_margin =
-          std::max(collapsed_strut.quirky_positive_margin,
-                   end_margin_strut.quirky_positive_margin);
-      collapsed_strut.negative_margin = std::max(
-          collapsed_strut.negative_margin, end_margin_strut.negative_margin);
-
-      // The extra space after the current box that would be added by ruby
-      // annotations, considering that the annotations eat into the following
-      // padding if it exists, and that we have already subtracted the block end
-      // padding from the clamp BFC offset.
-      LayoutUnit padding_annotation_overflow;
-      if (previous_inflow_position.block_end_annotation_space < LayoutUnit()) {
-        padding_annotation_overflow =
-            std::max(previous_inflow_position.block_end_annotation_space,
-                     -block_end_padding);
-      }
-
-      LayoutUnit bfc_offset = bfc_block_offset +
-                              previous_inflow_position.logical_block_offset +
-                              padding_annotation_overflow +
-                              (collapsed_strut.Sum() - end_margin_strut.Sum());
-
-      if (bfc_offset > data.clamp_bfc_offset) {
-        return false;
-      }
-
-      if (!layout_result->GetPhysicalFragment().IsFormattingContextRoot()) {
-        data.lines_until_clamp = layout_result->LinesUntilClamp();
-      }
+    // If the child advanced the number of lines, then it clamped after a line.
+    if (layout_result->LinesUntilClamp() != data.lines_until_clamp) {
+      return nullptr;
     }
-
-    return true;
+    // The child must have overflown at the beginning of the box. Since the
+    // beginning of a child box isn't a valid clamp point, we must clamp before
+    // it instead. If the previous child was a lineless box, we return that
+    // layout object.
+    return last_layout_object;
   }
 
   LineClampData data;
@@ -210,6 +140,10 @@
   // remaining lines in this block box would not exist if we weren't
   // ellipsizing. Can only be set if data.state == kClampByLines.
   bool ignore_further_lines = false;
+
+  // The last LayoutObject encountered since the last line.
+  // Can only be set if data.state == kMeasureLinesUntilBfcOffset.
+  const LayoutObject* last_layout_object = nullptr;
 };
 
 // A class for general block layout (e.g. a <div> with no special style).
@@ -237,8 +171,9 @@
       const InlineNode& child);
 
   NOINLINE const LayoutResult* RelayoutIgnoringLineClamp();
-  NOINLINE const LayoutResult* RelayoutWithLineClampBlockSize(
-      int lines_until_clamp);
+  NOINLINE const LayoutResult* RelayoutClampingByLines(int lines_until_clamp);
+  NOINLINE const LayoutResult* RelayoutClampingAfterLayoutObject(
+      const LayoutObject*);
   NOINLINE const LayoutResult* RelayoutForTextBoxTrimEnd();
 
   inline const LayoutResult* Layout(
diff --git a/third_party/blink/renderer/core/layout/fragment_builder.h b/third_party/blink/renderer/core/layout/fragment_builder.h
index 1bd8fb5..38db827d 100644
--- a/third_party/blink/renderer/core/layout/fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/fragment_builder.h
@@ -155,6 +155,10 @@
     would_be_last_line_if_not_for_ellipsis_ = true;
   }
 
+  void SetLineClampAfterLayoutObject(const LayoutObject* layout_object) {
+    line_clamp_after_layout_object_ = layout_object;
+  }
+
   bool IsBlockEndTrimmableLine() const { return is_block_end_trimmable_line_; }
   void SetIsBlockEndTrimmableLine() { is_block_end_trimmable_line_ = true; }
 
@@ -592,6 +596,7 @@
   MarginStrut end_margin_strut_;
   ExclusionSpace exclusion_space_;
   std::optional<int> lines_until_clamp_;
+  const LayoutObject* line_clamp_after_layout_object_ = nullptr;
 
   ChildrenVector children_;
 
diff --git a/third_party/blink/renderer/core/layout/frame_set_layout_algorithm.cc b/third_party/blink/renderer/core/layout/frame_set_layout_algorithm.cc
index b6ef7ad..4d8b7d9 100644
--- a/third_party/blink/renderer/core/layout/frame_set_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/frame_set_layout_algorithm.cc
@@ -177,7 +177,7 @@
   // proportionally over all relative columns/rows.
   // NOTE: the relative value of 0* is treated as 1*.
   if (!relative_indices.empty()) {
-    wtf_size_t last_relative_index = WTF::kNotFound;
+    wtf_size_t last_relative_index = kNotFound;
     int64_t remaining_relative = remaining_length.ToInt();
     for (auto i : relative_indices) {
       sizes[i] = IntLayoutUnit(
diff --git a/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc b/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc
index 8a57042..989cefd 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_items_builder.cc
@@ -1551,6 +1551,7 @@
                                              : uchar::kRightToLeftIsolate,
                    nullptr);
       AppendOpaque(InlineItem::kRubyLinePlaceholder, nullptr);
+      is_score_line_break_disabled_ = true;
     } else {
       AppendOpaque(InlineItem::kRubyLinePlaceholder, node->Parent());
     }
@@ -1580,6 +1581,7 @@
       ++ruby_text_nesting_level_;
     }
     AppendOpaque(InlineItem::kRubyLinePlaceholder, node);
+    is_score_line_break_disabled_ = true;
   } else if (node->IsInlineRubyText()) {
     AppendOpaque(InlineItem::kRubyLinePlaceholder, node);
   }
@@ -1680,6 +1682,7 @@
                        : uchar::kRightToLeftIsolate,
                    ruby_container);
       AppendOpaque(InlineItem::kRubyLinePlaceholder, node);
+      is_score_line_break_disabled_ = true;
     } else {
       AppendOpaque(InlineItem::kCloseRubyColumn, uchar::kPopDirectionalIsolate,
                    nullptr);
diff --git a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
index 042e72f..6a1de38c 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.cc
@@ -757,9 +757,8 @@
       space.ShouldTextBoxTrimFragmentainerEnd() ||
       space.ShouldTextBoxTrimInsideWhenLineClamp()) [[unlikely]] {
     LineClampData line_clamp_data = space.GetLineClampData();
-    bool is_truncated =
-        line_clamp_data.IsAtClampPoint() ||
-        line_clamp_data.state == LineClampData::kMeasureLinesUntilBfcOffset;
+    bool is_truncated = line_clamp_data.IsAtClampPoint() ||
+                        line_clamp_data.IsMeasureUntilBfcOffset();
     ApplyTextBoxTrim(*line_info, is_truncated);
   }
 
@@ -1686,12 +1685,11 @@
         end_margin_strut_ = MarginStrut();
 
         if (lines_until_clamp_) {
-          if (constraint_space.GetLineClampData().state ==
-              LineClampData::kClampByLines) {
+          if (constraint_space.GetLineClampData().IsClampByLines()) {
             *lines_until_clamp_ = *lines_until_clamp_ - 1;
           } else {
-            DCHECK_EQ(constraint_space.GetLineClampData().state,
-                      LineClampData::kMeasureLinesUntilBfcOffset);
+            DCHECK(
+                constraint_space.GetLineClampData().IsMeasureUntilBfcOffset());
             *lines_until_clamp_ = *lines_until_clamp_ + 1;
           }
         }
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node.cc b/third_party/blink/renderer/core/layout/inline/inline_node.cc
index ec9f9ce..be3d66c 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_node.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_node.cc
@@ -1763,8 +1763,8 @@
   HeapHashSet<Member<LayoutObject>> associated_objects;
 #endif
   InlineItems& items = data->items;
-  WTF::wtf_size_t size = items.size();
-  for (WTF::wtf_size_t i = 0; i != size;) {
+  wtf_size_t size = items.size();
+  for (wtf_size_t i = 0; i != size;) {
     LayoutObject* object = items[i]->GetLayoutObject();
     auto* layout_text = DynamicTo<LayoutText>(object);
     if (layout_text && !layout_text->IsBR()) {
@@ -1774,7 +1774,7 @@
 #endif
       layout_text->ClearHasBidiControlInlineItems();
       bool has_bidi_control = false;
-      WTF::wtf_size_t begin = i;
+      wtf_size_t begin = i;
       for (++i; i != size; ++i) {
         const InlineItem& item = *items[i];
         if (item.GetLayoutObject() != object)
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.cc b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
index 8c6f3fa..5acf4a90 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
@@ -2698,7 +2698,7 @@
       if (ComputeTrailingCollapsibleSpaceHelper(
               item_result.ruby_column->base_line)) {
         if (trailing_collapsible_space_ &&
-            trailing_collapsible_space_->item_result_index != WTF::kNotFound) {
+            trailing_collapsible_space_->item_result_index != kNotFound) {
           trailing_collapsible_space_->ancestor_ruby_columns.push_back(
               std::make_pair(line_info.MutableResults(),
                              std::distance(line_info.MutableResults()->data(),
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.h b/third_party/blink/renderer/core/layout/inline/line_breaker.h
index 8264e9b..fcc8968 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.h
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.h
@@ -464,7 +464,7 @@
 
    public:
     InlineItemResults* item_results = nullptr;
-    wtf_size_t item_result_index = WTF::kNotFound;
+    wtf_size_t item_result_index = kNotFound;
     const ShapeResultView* collapsed_shape_result = nullptr;
     // Ancestors of `item_result`. ancestor_ruby_columns[0] is the parent of
     // `item_result`, and ancestor_ruby_columns[n+1] is the parent of
diff --git a/third_party/blink/renderer/core/layout/inline/line_truncator.h b/third_party/blink/renderer/core/layout/inline/line_truncator.h
index 141e3ad..936547c9 100644
--- a/third_party/blink/renderer/core/layout/inline/line_truncator.h
+++ b/third_party/blink/renderer/core/layout/inline/line_truncator.h
@@ -50,7 +50,7 @@
   LayoutUnit PlaceEllipsisNextTo(LogicalLineItems* line_box,
                                  LogicalLineItem* ellipsized_child);
 
-  static constexpr wtf_size_t kDidNotAddChild = WTF::kNotFound;
+  static constexpr wtf_size_t kDidNotAddChild = kNotFound;
   // Add a child with truncated text of (*line_box)[source_index].
   // This function returns the index of the new child.
   // If the truncated text is empty, kDidNotAddChild is returned.
diff --git a/third_party/blink/renderer/core/layout/inline/ruby_utils.cc b/third_party/blink/renderer/core/layout/inline/ruby_utils.cc
index 6fc11de..76cf13a 100644
--- a/third_party/blink/renderer/core/layout/inline/ruby_utils.cc
+++ b/third_party/blink/renderer/core/layout/inline/ruby_utils.cc
@@ -121,24 +121,23 @@
                                        wtf_size_t start_item_index) {
   CHECK_LT(start_item_index, items.size());
   CHECK_EQ(items[start_item_index]->Type(), InlineItem::kOpenRubyColumn);
-  RubyItemIndexes indexes = {start_item_index, WTF::kNotFound, WTF::kNotFound,
-                             WTF::kNotFound};
+  RubyItemIndexes indexes = {start_item_index, kNotFound, kNotFound, kNotFound};
   for (wtf_size_t i = start_item_index + 1; i < items.size(); ++i) {
     const InlineItem& item = *items[i];
     if (item.Type() == InlineItem::kCloseRubyColumn) {
-      if (indexes.base_end == WTF::kNotFound) {
-        DCHECK_EQ(indexes.annotation_start, WTF::kNotFound);
+      if (indexes.base_end == kNotFound) {
+        DCHECK_EQ(indexes.annotation_start, kNotFound);
         indexes.base_end = i;
       } else {
-        DCHECK_NE(indexes.annotation_start, WTF::kNotFound);
+        DCHECK_NE(indexes.annotation_start, kNotFound);
       }
       indexes.column_end = i;
       return indexes;
     }
     if (item.Type() == InlineItem::kOpenTag &&
         item.GetLayoutObject()->IsInlineRubyText()) {
-      DCHECK_EQ(indexes.base_end, WTF::kNotFound);
-      DCHECK_EQ(indexes.annotation_start, WTF::kNotFound);
+      DCHECK_EQ(indexes.base_end, kNotFound);
+      DCHECK_EQ(indexes.annotation_start, kNotFound);
       indexes.base_end = i;
       indexes.annotation_start = i;
     } else if (item.Type() == InlineItem::kOpenRubyColumn) {
diff --git a/third_party/blink/renderer/core/layout/inline/ruby_utils.h b/third_party/blink/renderer/core/layout/inline/ruby_utils.h
index 61f6b80..2dbc1ce 100644
--- a/third_party/blink/renderer/core/layout/inline/ruby_utils.h
+++ b/third_party/blink/renderer/core/layout/inline/ruby_utils.h
@@ -28,7 +28,7 @@
   wtf_size_t column_start;
   // Points a kOpenTag for <rt> item or a kCloseRubyColumn item.
   wtf_size_t base_end;
-  // Points a kOpenTag for <rt> item, or WTF::kNotFound.
+  // Points a kOpenTag for <rt> item, or kNotFound.
   wtf_size_t annotation_start;
   // Points a kCloseRubyColumn item.
   wtf_size_t column_end;
diff --git a/third_party/blink/renderer/core/layout/inline/score_line_breaker_test.cc b/third_party/blink/renderer/core/layout/inline/score_line_breaker_test.cc
index 27c53539..f588419 100644
--- a/third_party/blink/renderer/core/layout/inline/score_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/inline/score_line_breaker_test.cc
@@ -428,6 +428,26 @@
   // Test pass if it doesn't crash.
 }
 
+TEST_F(ScoreLineBreakerTest, Ruby) {
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font-size: 16px;
+      text-wrap: balance;
+      width: 110px;
+    }
+    </style>
+    <div id="container">
+      <ruby>ruby<ruby>
+    </div>
+  )HTML");
+  const LayoutBlockFlow* container = GetLayoutBlockFlowByElementId("container");
+  const InlineNodeData* inline_node_data = container->GetInlineNodeData();
+  ASSERT_TRUE(inline_node_data);
+  EXPECT_TRUE(inline_node_data->IsScoreLineBreakDisabled());
+}
+
 TEST_F(ScoreLineBreakerTest, Zoom) {
   LoadAhem();
   SetBodyInnerHTML(R"HTML(
diff --git a/third_party/blink/renderer/core/layout/layout_algorithm.h b/third_party/blink/renderer/core/layout/layout_algorithm.h
index 39cf538..bbe7443 100644
--- a/third_party/blink/renderer/core/layout/layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/layout_algorithm.h
@@ -117,11 +117,12 @@
     kNoRelayout = 0,
     kRelayoutForEarlyBreak = 1,
     kRelayoutIgnoringLineClamp = 2,
-    kRelayoutWithLineClampBlockSize = 4,
+    kRelayoutClampingByLines = 4,
     kRelayoutForTextBoxTrim = 8,
     kRelayoutWithoutFragmentation = 16,
     kRelayoutIgnoringChildScrollbarChanges = 32,
     kRelayoutAsLastTableBox = 64,
+    kRelayoutClampingAfterLayoutObject = 128,
   };
   // Bitmask of active relayout types (`RelayoutType`).
   typedef int RelayoutMode;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 962c2787..4c0517a 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2732,7 +2732,7 @@
   const auto& box_fragment =
       To<PhysicalBoxFragment>(result->GetPhysicalFragment());
 
-  if (index != WTF::kNotFound && layout_results_.size() > index) {
+  if (index != kNotFound && layout_results_.size() > index) {
     if (layout_results_.size() > index + 1) {
       // If we have reached the end, remove surplus results from previous
       // layout.
diff --git a/third_party/blink/renderer/core/layout/layout_result.cc b/third_party/blink/renderer/core/layout/layout_result.cc
index b906cff..b030611 100644
--- a/third_party/blink/renderer/core/layout/layout_result.cc
+++ b/third_party/blink/renderer/core/layout/layout_result.cc
@@ -254,6 +254,10 @@
   if (builder->would_be_last_line_if_not_for_ellipsis_) {
     EnsureRareData()->set_would_be_last_line_if_not_for_ellipsis();
   }
+  if (builder->line_clamp_after_layout_object_) {
+    EnsureRareData()->line_clamp_after_layout_object =
+        builder->line_clamp_after_layout_object_;
+  }
 
   if (builder->tallest_unbreakable_block_size_ >= LayoutUnit()) {
     EnsureRareData()->tallest_unbreakable_block_size =
@@ -406,6 +410,7 @@
   visitor->Trace(non_overflowing_scroll_ranges);
   visitor->Trace(column_spanner_path);
   visitor->Trace(exclusion_space);
+  visitor->Trace(line_clamp_after_layout_object);
   visitor->Trace(accessibility_anchor);
   visitor->Trace(display_locks_affected_by_anchors);
 }
diff --git a/third_party/blink/renderer/core/layout/layout_result.h b/third_party/blink/renderer/core/layout/layout_result.h
index eab65cc..aa86ce07 100644
--- a/third_party/blink/renderer/core/layout/layout_result.h
+++ b/third_party/blink/renderer/core/layout/layout_result.h
@@ -112,6 +112,10 @@
     return rare_data_ ? rare_data_->lines_until_clamp : 0;
   }
 
+  const LayoutObject* LineClampAfterLayoutObject() const {
+    return rare_data_ ? rare_data_->line_clamp_after_layout_object : nullptr;
+  }
+
   // Returns true if the block-end of this line box is trimmable by the
   // `text-box-trim` property. If it's true, it means that this is the line box
   // that was the candidate for block-end trimming, but this doesn't necessarily
@@ -860,6 +864,8 @@
           annotation_overflow(rare_data.annotation_overflow),
           block_end_annotation_space(rare_data.block_end_annotation_space),
           lines_until_clamp(rare_data.lines_until_clamp),
+          line_clamp_after_layout_object(
+              rare_data.line_clamp_after_layout_object),
           line_box_bfc_block_offset(rare_data.line_box_bfc_block_offset),
           non_overflowing_scroll_ranges(
               rare_data.non_overflowing_scroll_ranges),
@@ -984,6 +990,7 @@
     LayoutUnit annotation_overflow;
     LayoutUnit block_end_annotation_space;
     int lines_until_clamp;
+    WeakMember<const LayoutObject> line_clamp_after_layout_object;
     Member<Element> accessibility_anchor;
     Member<GCedHeapHashSet<Member<Element>>> display_locks_affected_by_anchors;
 
diff --git a/third_party/blink/renderer/core/layout/layout_text_test.cc b/third_party/blink/renderer/core/layout/layout_text_test.cc
index bbe9a1d9..bffa4cd1 100644
--- a/third_party/blink/renderer/core/layout/layout_text_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_test.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/core/editing/testing/selection_sample.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_node_data.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
 
 namespace blink {
@@ -1700,8 +1699,7 @@
 TEST_F(LayoutTextTest, OriginalTextNullWhenTransformedTextIsNonNull) {
   // Setup CSS pseudo-element which generates a LayoutText without a DOM Text
   // node
-  if (RuntimeEnabledFeatures::UseOriginalDomOffsetsForOffsetMapEnabled()) {
-    SetBodyInnerHTML(R"HTML(
+  SetBodyInnerHTML(R"HTML(
     <style>
       #target::after {
         content: counter(fake-counter-name, disclosure-open);
@@ -1710,21 +1708,20 @@
     <div id="target"></div>
   )HTML");
 
-    // Get the LayoutText from the ::after pseudo-element
-    const Element& target = *GetElementById("target");
-    const Element& after = *target.GetPseudoElement(kPseudoIdAfter);
-    const auto& layout_text =
-        *To<LayoutText>(after.GetLayoutObject()->SlowFirstChild());
+  // Get the LayoutText from the ::after pseudo-element
+  const Element& target = *GetElementById("target");
+  const Element& after = *target.GetPseudoElement(kPseudoIdAfter);
+  const auto& layout_text =
+      *To<LayoutText>(after.GetLayoutObject()->SlowFirstChild());
 
-    // Check that OriginalText() returns empty string
-    EXPECT_TRUE(layout_text.OriginalText().empty());
+  // Check that OriginalText() returns empty string
+  EXPECT_TRUE(layout_text.OriginalText().empty());
 
-    // Check that text_ has content (through TransformedText which accesses it)
-    EXPECT_FALSE(layout_text.TransformedText().empty());
+  // Check that text_ has content (through TransformedText which accesses it)
+  EXPECT_FALSE(layout_text.TransformedText().empty());
 
-    // Verify we're dealing with a LayoutText that doesn't have a Text node
-    EXPECT_FALSE(DynamicTo<Text>(layout_text.GetNode()));
-  }
+  // Verify we're dealing with a LayoutText that doesn't have a Text node
+  EXPECT_FALSE(DynamicTo<Text>(layout_text.GetNode()));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/line_clamp_data.cc b/third_party/blink/renderer/core/layout/line_clamp_data.cc
index e9e70c7..1a91f88 100644
--- a/third_party/blink/renderer/core/layout/line_clamp_data.cc
+++ b/third_party/blink/renderer/core/layout/line_clamp_data.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/layout/line_clamp_data.h"
 
+#include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
 
 namespace blink {
@@ -11,8 +12,9 @@
 namespace {
 
 struct SameSizeAsLineClampData {
-  LayoutUnit clamp_bfc_offset;
   int lines_until_clamp;
+  LayoutUnit clamp_bfc_offset;
+  UntracedMember<const LayoutObject> clamp_after_layout_object;
   int state;
 };
 
@@ -20,4 +22,46 @@
 
 }  // namespace
 
+CORE_EXPORT LineClampData::LineClampData(const LineClampData& o)
+    : state(o.state) {
+  switch (state) {
+    case kDisabled:
+      break;
+    case kClampByLines:
+      lines_until_clamp = o.lines_until_clamp;
+      break;
+    case kClampAfterLayoutObject:
+      clamp_after_layout_object = o.clamp_after_layout_object;
+      break;
+    case kMeasureLinesUntilBfcOffset:
+    case kClampByLinesWithBfcOffset:
+      lines_until_clamp = o.lines_until_clamp;
+      clamp_bfc_offset = o.clamp_bfc_offset;
+      break;
+  }
+}
+
+CORE_EXPORT LineClampData& LineClampData::operator=(const LineClampData& o) {
+  if (state == kClampAfterLayoutObject && o.state != kClampAfterLayoutObject) {
+    clamp_after_layout_object.Clear();
+  }
+  state = o.state;
+  switch (state) {
+    case kDisabled:
+      break;
+    case kClampByLines:
+      lines_until_clamp = o.lines_until_clamp;
+      break;
+    case kClampAfterLayoutObject:
+      clamp_after_layout_object = o.clamp_after_layout_object;
+      break;
+    case kMeasureLinesUntilBfcOffset:
+    case kClampByLinesWithBfcOffset:
+      lines_until_clamp = o.lines_until_clamp;
+      clamp_bfc_offset = o.clamp_bfc_offset;
+      break;
+  }
+  return *this;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/line_clamp_data.h b/third_party/blink/renderer/core/layout/line_clamp_data.h
index a25388b6..a162ae6c 100644
--- a/third_party/blink/renderer/core/layout/line_clamp_data.h
+++ b/third_party/blink/renderer/core/layout/line_clamp_data.h
@@ -7,26 +7,43 @@
 
 #include <optional>
 
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
+class LayoutObject;
 
 struct LineClampData {
   DISALLOW_NEW();
 
-  LineClampData() {}
+  LineClampData() = default;
+
+  CORE_EXPORT LineClampData(const LineClampData&);
+
+  CORE_EXPORT LineClampData& operator=(const LineClampData&);
 
   enum State {
     kDisabled,
     kClampByLines,
+    kClampAfterLayoutObject,
     kMeasureLinesUntilBfcOffset,
+    kClampByLinesWithBfcOffset,
   };
 
   bool IsLineClampContext() const { return state != kDisabled; }
 
+  bool IsClampByLines() const {
+    return state == kClampByLines || state == kClampByLinesWithBfcOffset;
+  }
+  bool IsMeasureUntilBfcOffset() const {
+    return state == kMeasureLinesUntilBfcOffset ||
+           state == kClampByLinesWithBfcOffset;
+  }
+
   std::optional<int> LinesUntilClamp(bool show_measured_lines = false) const {
-    if (state == kClampByLines ||
+    if (IsClampByLines() ||
         (show_measured_lines && state == kMeasureLinesUntilBfcOffset)) {
       return lines_until_clamp;
     }
@@ -34,11 +51,11 @@
   }
 
   bool IsAtClampPoint() const {
-    return state == kClampByLines && lines_until_clamp == 1;
+    return IsClampByLines() && lines_until_clamp == 1;
   }
 
   bool IsPastClampPoint() const {
-    return state == kClampByLines && lines_until_clamp <= 0;
+    return IsClampByLines() && lines_until_clamp <= 0;
   }
 
   bool ShouldHideForPaint() const {
@@ -52,7 +69,10 @@
     switch (state) {
       case kClampByLines:
         return lines_until_clamp == other.lines_until_clamp;
+      case kClampAfterLayoutObject:
+        return clamp_after_layout_object == other.clamp_after_layout_object;
       case kMeasureLinesUntilBfcOffset:
+      case kClampByLinesWithBfcOffset:
         return lines_until_clamp == other.lines_until_clamp &&
                clamp_bfc_offset == other.clamp_bfc_offset;
       default:
@@ -60,18 +80,36 @@
     }
   }
 
-  // The BFC offset where the current block container should clamp.
-  // (Might not be the same BFC offset as other block containers in the same
-  // BFC, depending on the bottom bmp).
-  // Only valid if state == kClampByBfcOffset
-  LayoutUnit clamp_bfc_offset;
-
-  // If state == kClampByLines, the number of lines until the clamp point.
-  // A value of 1 indicates the current line should be clamped. May go negative.
+  // If state == kClampByLines or kClampByLinesWithBfcOffset, the number of
+  // lines until the clamp point. A value of 1 indicates the current line should
+  // be clamped. May go negative.
   // With state == kMeasureLinesUntilBfcOffset, the number of lines found in the
   // BFC so far.
   int lines_until_clamp = 0;
 
+  // The BFC offset where the current block container should clamp.
+  // (Might not be the same BFC offset as other block containers in the same
+  // BFC, depending on the bottom bmp).
+  // Only valid if state == kMeasureLinesUntilBfcOffset or
+  // kClampByLinesWithBfcOffset.
+  LayoutUnit clamp_bfc_offset;
+
+  // A LayoutObject immediately after which the container should clamp.
+  // This is used to clamp after a lineless block when clamping by a height.
+  //
+  // This UntracedMember should not be dereferenced, it should only ever be used
+  // to compare pointer equality.
+  //
+  // Even though it should not be dereferenced, we don't expect LineClampData
+  // objects to live past the end of the layout phase; and the LayoutObject is
+  // part of the input to that phase. So we can be somewhat confident that the
+  // LayoutObject won't be GC'd and therefore that its address won't be reused
+  // for a different LayoutObject during the LineClampData's lifetime. So using
+  // it for pointer equality should not run into false positives.
+  //
+  // Only valid if state == kClampAfterLayoutObject.
+  UntracedMember<const LayoutObject> clamp_after_layout_object;
+
   State state = kDisabled;
 };
 
diff --git a/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc
index c150c78..9a77cea5 100644
--- a/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/out_of_flow_layout_part.cc
@@ -1512,7 +1512,7 @@
   // add repeated elements to every fragmentainer that exists, but if there's a
   // nested OOF that triggers creation of additional fragmentainers, we'll need
   // to add the fixed-positioned elements to those as well.
-  wtf_size_t previous_repeaded_fixedpos_resume_idx = WTF::kNotFound;
+  wtf_size_t previous_repeaded_fixedpos_resume_idx = kNotFound;
 
   while (!descendants->empty()) {
     ComputeInlineContainingBlocksForFragmentainer(*descendants);
@@ -1690,7 +1690,7 @@
         // fragmentainers in the next iteration (because of nested OOFs), we
         // need to resume those when a new fragmentainer is added.
         DCHECK(container_builder_->Node().IsPaginatedRoot());
-        DCHECK(previous_repeaded_fixedpos_resume_idx == WTF::kNotFound ||
+        DCHECK(previous_repeaded_fixedpos_resume_idx == kNotFound ||
                previous_repeaded_fixedpos_resume_idx <=
                    descendants_to_layout.size());
         previous_repeaded_fixedpos_resume_idx = descendants_to_layout.size();
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc b/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc
index ae2ff86..7bae27b 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.cc
@@ -608,7 +608,7 @@
   }
 
   wtf_size_t range_index = 0;
-  wtf_size_t in_path_index = WTF::kNotFound;
+  wtf_size_t in_path_index = kNotFound;
   std::unique_ptr<PathPositionMapper> path_mapper;
 
   // 2. Set the "in path" flag to false.
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.h b/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.h
index 658bebec..fd15fc7 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_algorithm.h
@@ -83,7 +83,7 @@
     float length_adjust_scale = 1.0f;
     float text_length_shift_x = 0.0f;
     float text_length_shift_y = 0.0f;
-    wtf_size_t item_index = WTF::kNotFound;
+    wtf_size_t item_index = kNotFound;
   };
   // This data member represents "result" defined in the specification, but it
   // contains only addressable characters.
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_query.cc b/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
index e0eb68c..11035e89 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
@@ -103,7 +103,7 @@
     return {item, item_text, item->StartOffset() + i,
             item->StartOffset() + item_text.NextCodePointOffset(i)};
   }
-  return {nullptr, StringView(), WTF::kNotFound, WTF::kNotFound};
+  return {nullptr, StringView(), kNotFound, kNotFound};
 }
 
 void GetCanvasRotation(void* context,
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index d01bca6c..0150215 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -550,75 +550,6 @@
                          LinkLoaderModulePreloadTest,
                          testing::ValuesIn(kModulePreloadTestParams));
 
-class LinkLoaderTestPrefetchPrivacyChanges
-    : public testing::Test,
-      public testing::WithParamInterface<bool>,
-      private ScopedMockOverlayScrollbars {
- public:
-  LinkLoaderTestPrefetchPrivacyChanges()
-      : privacy_changes_enabled_(GetParam()) {}
-  void SetUp() override {
-    std::vector<base::test::FeatureRef> enable_features;
-    std::vector<base::test::FeatureRef> disabled_features;
-    if (GetParam()) {
-      enable_features.push_back(features::kPrefetchPrivacyChanges);
-    } else {
-      disabled_features.push_back(features::kPrefetchPrivacyChanges);
-    }
-    feature_list_.InitWithFeatures(enable_features, disabled_features);
-  }
-
- protected:
-  const bool privacy_changes_enabled_;
-  test::TaskEnvironment task_environment_;
-  ScopedTestingPlatformSupport<TestingPlatformSupport> platform_;
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-};
-
-INSTANTIATE_TEST_SUITE_P(LinkLoaderTestPrefetchPrivacyChanges,
-                         LinkLoaderTestPrefetchPrivacyChanges,
-                         testing::Values(false, true));
-
-TEST_P(LinkLoaderTestPrefetchPrivacyChanges, PrefetchPrivacyChanges) {
-  auto dummy_page_holder =
-      std::make_unique<DummyPageHolder>(gfx::Size(500, 500));
-  dummy_page_holder->GetFrame().GetSettings()->SetScriptEnabled(true);
-  Persistent<MockLinkLoaderClient> loader_client =
-      MakeGarbageCollected<MockLinkLoaderClient>(true);
-  auto* loader = MakeGarbageCollected<LinkLoader>(loader_client.Get());
-  KURL href_url = KURL(NullURL(), "http://example.test/cat.jpg");
-  // TODO(crbug.com/751425): We should use the mock functionality
-  // via |dummy_page_holder|.
-  url_test_helpers::RegisterMockedErrorURLLoad(href_url);
-  LinkLoadParameters params(
-      LinkRelAttribute("prefetch"), kCrossOriginAttributeNotSet, "image/jpg",
-      "", "", "", "", String(), network::mojom::ReferrerPolicy::kDefault,
-      href_url, String() /* image_srcset */, String() /* image_sizes */,
-      String() /* blocking */);
-  loader->LoadLink(params, dummy_page_holder->GetDocument());
-  ASSERT_TRUE(dummy_page_holder->GetDocument().Fetcher());
-  Resource* resource = loader->GetResourceForTesting();
-  EXPECT_TRUE(resource);
-
-  if (privacy_changes_enabled_) {
-    EXPECT_EQ(resource->GetResourceRequest().GetRedirectMode(),
-              network::mojom::RedirectMode::kError);
-    EXPECT_EQ(resource->GetResourceRequest().GetReferrerPolicy(),
-              network::mojom::ReferrerPolicy::kNever);
-  } else {
-    EXPECT_EQ(resource->GetResourceRequest().GetRedirectMode(),
-              network::mojom::RedirectMode::kFollow);
-    EXPECT_EQ(resource->GetResourceRequest().GetReferrerPolicy(),
-              ReferrerUtils::MojoReferrerPolicyResolveDefault(
-                  network::mojom::ReferrerPolicy::kDefault));
-  }
-
-  URLLoaderMockFactory::GetSingletonInstance()
-      ->UnregisterAllURLsAndClearMemoryCache();
-}
-
 class LinkLoaderTest : public testing::Test,
                        private ScopedMockOverlayScrollbars {
  protected:
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index 1b56df0..3e7e4cf 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -590,7 +590,7 @@
   // permission for the LNA request to go through.
   //
   // Reference:
-  // https://github.com/explainers-by-googlers/local-network-access
+  // https://wicg.github.io/local-network-access/
   //
   // This only checks for mixed content subresources; subframe navigation mixed
   // content is checked in
@@ -947,7 +947,7 @@
   // considered secure and not mixed content.
   //
   // Reference:
-  // https://github.com/explainers-by-googlers/local-network-access
+  // https://wicg.github.io/local-network-access/
   //
   // TODO(crbug.com/395895368): check the IP address space for initiator, only
   // skip when the initiator is more public.
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index 9f048147..a87f3cf 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -781,13 +781,6 @@
   resource_request.SetFetchPriorityHint(
       GetFetchPriorityAttributeValue(params.fetch_priority_hint));
 
-  if (base::FeatureList::IsEnabled(features::kPrefetchPrivacyChanges)) {
-    resource_request.SetRedirectMode(network::mojom::RedirectMode::kError);
-    resource_request.SetReferrerPolicy(network::mojom::ReferrerPolicy::kNever);
-    // TODO(domfarolino): Implement more privacy-preserving prefetch changes.
-    // See crbug.com/988956.
-  }
-
   ResourceLoaderOptions options(
       document.GetExecutionContext()->GetCurrentWorld());
   options.initiator_info.name = fetch_initiator_type_names::kLink;
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index e504d1c..5e7f38b 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -426,6 +426,11 @@
     should_prepare_paint_tree_on_prerender_ =
         should_prepare_paint_tree_on_prerender;
   }
+  void SetShouldPauseJavaScriptExecutionOnPrerender(
+      bool should_pause_javascript_execution_on_prerender) {
+    should_pause_javascript_execution_on_prerender_ =
+        should_pause_javascript_execution_on_prerender;
+  }
   bool IsPrerendering() const { return is_prerendering_; }
   const String& PrerenderMetricSuffix() const {
     return prerender_metric_suffix_;
@@ -703,13 +708,16 @@
   // this Page. Once initialized, it can only transition from true to false on
   // prerender activation; it does not go from false to true.
   bool is_prerendering_ = false;
-  String prerender_metric_suffix_;
 
+  // TODO(crbug.com/428500219): Do not flatten these params.
+  String prerender_metric_suffix_;
   // If true, warms up compositor on `WebLocalFrameImpl::DidCommitLoad` if the
   // page is under prerendering.
   bool should_warm_up_compositor_on_prerender_ = false;
   // If true, prepares the paint tree if the page is under prerendering.
   bool should_prepare_paint_tree_on_prerender_ = false;
+  // If true, pauses JavaScript execution until the page is activated.
+  bool should_pause_javascript_execution_on_prerender_ = false;
 
   // Whether the the Page's main document is a Fenced Frame document. This is
   // only set for the MPArch implementation and is true when the corresponding
diff --git a/third_party/blink/renderer/core/paint/fragment_data_iterator.h b/third_party/blink/renderer/core/paint/fragment_data_iterator.h
index 24e4a64..eb30966e 100644
--- a/third_party/blink/renderer/core/paint/fragment_data_iterator.h
+++ b/third_party/blink/renderer/core/paint/fragment_data_iterator.h
@@ -35,13 +35,13 @@
     }
     idx_++;
     if (idx_ >= fragment_head_.size()) {
-      idx_ = WTF::kNotFound;
+      idx_ = kNotFound;
       return false;
     }
     return true;
   }
 
-  bool IsDone() const { return idx_ == WTF::kNotFound; }
+  bool IsDone() const { return idx_ == kNotFound; }
 
   Iterator& begin() {
     DCHECK_EQ(idx_, 0u);
@@ -49,7 +49,7 @@
   }
   Iterator end() {
     Iterator end_it(*static_cast<Iterator*>(this));
-    end_it.idx_ = WTF::kNotFound;
+    end_it.idx_ = kNotFound;
     return end_it;
   }
   bool operator!=(const Iterator& other) {
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index ecc8d93e..b2e60a1 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1584,7 +1584,7 @@
       // transform, though, we'll only have one PaintLayerFragment in the list
       // at this point (we iterate over them further up on the stack, and pass a
       // "list" of one fragment at a time from there instead).
-      DCHECK(fragment.fragment_idx != WTF::kNotFound);
+      DCHECK(fragment.fragment_idx != kNotFound);
       HitTestLocation location_for_fragment(hit_test_location,
                                             fragment.fragment_idx);
       if (HitTestFragmentWithPhase(result, fragment.physical_fragment,
diff --git a/third_party/blink/renderer/core/paint/paint_layer_fragment.h b/third_party/blink/renderer/core/paint/paint_layer_fragment.h
index 230a150..20afdf1d 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_fragment.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_fragment.h
@@ -77,7 +77,7 @@
   ClipRect foreground_rect;
 
   // The fragment index of fragment_data / physical_fragment.
-  wtf_size_t fragment_idx = WTF::kNotFound;
+  wtf_size_t fragment_idx = kNotFound;
 
   // The corresponding FragmentData of this structure.
   Member<const FragmentData> fragment_data = nullptr;
diff --git a/third_party/blink/renderer/core/paint/timing/paint_timing.cc b/third_party/blink/renderer/core/paint/timing/paint_timing.cc
index d72654c..fe19321 100644
--- a/third_party/blink/renderer/core/paint/timing/paint_timing.cc
+++ b/third_party/blink/renderer/core/paint/timing/paint_timing.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/functional/callback_forward.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -65,6 +66,12 @@
   base::TimeTicks rendering_update_end_time;
 };
 
+// When enabled, `PaintTiming::MarkPaintTimingInternal()` is only called from
+// `PaintTiming::NotifyPaintFinished()`.
+BASE_FEATURE(kMarkPaintTimingInternalOnlyOnFinish,
+             "MarkPaintTimingInternalOnlyOnFinish",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 }  // namespace
 
 class RecodingTimeAfterBackForwardCacheRestoreFrameCallback
@@ -232,7 +239,10 @@
 
   if (is_first_paint)
     GetFrame()->OnFirstPaint(text_painted, image_painted);
-  MarkPaintTimingInternal();
+
+  if (!base::FeatureList::IsEnabled(kMarkPaintTimingInternalOnlyOnFinish)) {
+    MarkPaintTimingInternal();
+  }
 }
 
 // https://w3c.github.io/paint-timing/#mark-paint-timing
diff --git a/third_party/blink/renderer/core/patching/dom_patch_status.cc b/third_party/blink/renderer/core/patching/dom_patch_status.cc
index d1ec50c..da8cd18 100644
--- a/third_party/blink/renderer/core/patching/dom_patch_status.cc
+++ b/third_party/blink/renderer/core/patching/dom_patch_status.cc
@@ -5,49 +5,64 @@
 #include "third_party/blink/renderer/core/patching/dom_patch_status.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/mutation_observer.h"
 #include "third_party/blink/renderer/core/dom/parser_content_policy.h"
 #include "third_party/blink/renderer/core/event_type_names.h"
 #include "third_party/blink/renderer/core/html/html_template_element.h"
 #include "third_party/blink/renderer/core/html/parser/html_document_parser.h"
+#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
 #include "third_party/blink/renderer/core/patching/patch_event.h"
 #include "third_party/blink/renderer/core/patching/patch_supplement.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
 
 namespace blink {
 // static
-DOMPatchStatus* DOMPatchStatus::Start(HTMLTemplateElement& source,
-                                      ContainerNode& target) {
-  // A patch replaces the existing children of the target.
-  target.RemoveChildren();
-  DOMPatchStatus* patch = MakeGarbageCollected<DOMPatchStatus>(source, target);
-  MutationObserver::EnqueuePatch(*patch);
-  PatchSupplement::From(target.GetDocument())->DidStart(target, patch);
-  return patch;
+DOMPatchStatus* DOMPatchStatus::Create(ContainerNode& target,
+                                       HTMLTemplateElement* source) {
+  return MakeGarbageCollected<DOMPatchStatus>(source, target);
 }
 
-DOMPatchStatus::DOMPatchStatus(HTMLTemplateElement& source,
+DOMPatchStatus::DOMPatchStatus(HTMLTemplateElement* source,
                                ContainerNode& target)
     : source_(source),
       target_(target),
       finished_(
           MakeGarbageCollected<ScriptPromiseProperty<IDLUndefined, IDLAny>>(
-              target.GetDocument().GetExecutionContext())),
-      parser_(MakeGarbageCollected<HTMLDocumentParser>(
-          target_,
-          target.IsElementNode() ? &To<Element>(target)
-                                 : target.parentElement(),
-          ParserContentPolicy::kDisallowScriptingAndPluginContent)) {}
+              target.GetDocument().GetExecutionContext())) {}
 
 ScriptPromise<IDLUndefined> DOMPatchStatus::finished(
     ScriptState* script_state) {
   return finished_->Promise(script_state->World());
 }
 
+void DOMPatchStatus::Start() {
+  if (state_ != State::kPending) {
+    return;
+  }
+  state_ = State::kActive;
+  // A patch replaces the existing children of the target.
+  target_->RemoveChildren();
+  MutationObserver::EnqueuePatch(*this);
+  PatchSupplement::From(GetDocument())->DidStart(*target_, this);
+  parser_ = MakeGarbageCollected<HTMLDocumentParser>(
+      target_,
+      target_->IsElementNode() ? &To<Element>(*target_)
+                               : target_->parentElement(),
+      ParserContentPolicy::kDisallowScriptingAndPluginContent);
+  if (parser_->NeedsDecoder()) {
+    parser_->SetDecoder(
+        std::make_unique<TextResourceDecoder>(TextResourceDecoderOptions(
+            TextResourceDecoderOptions::ContentType::kHTMLContent,
+            GetDocument().Encoding())));
+  }
+}
+
 void DOMPatchStatus::DispatchPatchEvent() {
   Event* event =
       MakeGarbageCollected<PatchEvent>(event_type_names::kPatch, this);
@@ -56,6 +71,11 @@
 }
 
 void DOMPatchStatus::Finish() {
+  if (state_ != State::kActive) {
+    CHECK_EQ(state_, State::kTerminated);
+    return;
+  }
+  state_ = State::kFinished;
   parser_->Finish();
   finished_->ResolveWithUndefined();
   PatchSupplement::From(GetDocument())->DidComplete(*target_);
@@ -74,7 +94,25 @@
 }
 
 void DOMPatchStatus::Append(const String& text) {
-  parser_->Append(text);
+  if (state_ == State::kActive) {
+    parser_->Append(text);
+  }
+}
+
+void DOMPatchStatus::Terminate(ScriptValue reason) {
+  if (state_ == State::kFinished || state_ == State::kTerminated) {
+    return;
+  }
+
+  state_ = State::kTerminated;
+
+  finished_->Reject(reason);
+  parser_->Finish();
+  PatchSupplement::From(GetDocument())->DidComplete(*target_);
+}
+
+void DOMPatchStatus::AppendBytes(base::span<uint8_t> bytes) {
+  parser_->AppendBytes(bytes);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/patching/dom_patch_status.h b/third_party/blink/renderer/core/patching/dom_patch_status.h
index 0dedfd7..69ae887 100644
--- a/third_party/blink/renderer/core/patching/dom_patch_status.h
+++ b/third_party/blink/renderer/core/patching/dom_patch_status.h
@@ -22,13 +22,14 @@
 namespace blink {
 class HTMLTemplateElement;
 class ScriptState;
+
 class DOMPatchStatus : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static DOMPatchStatus* Start(HTMLTemplateElement& source,
-                               ContainerNode& target);
-  DOMPatchStatus(HTMLTemplateElement& source, ContainerNode& target);
+  static DOMPatchStatus* Create(ContainerNode& target,
+                                HTMLTemplateElement* source = nullptr);
+  DOMPatchStatus(HTMLTemplateElement* source, ContainerNode& target);
   ScriptPromise<IDLUndefined> finished(ScriptState*);
   HTMLTemplateElement* source() { return source_; }
   void Trace(Visitor*) const override;
@@ -37,9 +38,14 @@
   Document& GetDocument();
   void DispatchPatchEvent();
   void Append(const String&);
+  void Start();
   void Finish();
+  void Terminate(ScriptValue);
+  void AppendBytes(base::span<uint8_t>);
 
  private:
+  enum class State { kPending, kActive, kTerminated, kFinished };
+  State state_ = State::kPending;
   Member<HTMLTemplateElement> source_;
   Member<ContainerNode> target_;
   Member<ScriptPromiseProperty<IDLUndefined, IDLAny>> finished_;
diff --git a/third_party/blink/renderer/core/patching/patch_supplement.cc b/third_party/blink/renderer/core/patching/patch_supplement.cc
index bf158d6..057834d 100644
--- a/third_party/blink/renderer/core/patching/patch_supplement.cc
+++ b/third_party/blink/renderer/core/patching/patch_supplement.cc
@@ -6,16 +6,88 @@
 
 #include <optional>
 
+#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h"
+#include "third_party/blink/renderer/core/dom/container_node.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/patching/dom_patch_status.h"
+#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
+#include "third_party/blink/renderer/core/streams/writable_stream.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
 #include "third_party/blink/renderer/platform/graphics/dom_node_id.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
+#include "v8-primitive.h"
 
 namespace blink {
 
 // static
 const char PatchSupplement::kSupplementName[] = "Patch";
 
+namespace {
+class SinglePatchSink : public UnderlyingSinkBase {
+ public:
+  explicit SinglePatchSink(ContainerNode& target)
+      : patch_(DOMPatchStatus::Create(target)) {}
+  void Trace(Visitor* visitor) const override {
+    visitor->Trace(patch_);
+    UnderlyingSinkBase::Trace(visitor);
+  }
+
+ private:
+  ScriptPromise<IDLUndefined> start(ScriptState* script_state,
+                                    WritableStreamDefaultController*,
+                                    ExceptionState&) override {
+    patch_->Start();
+    return ToResolvedUndefinedPromise(script_state);
+  }
+  ScriptPromise<IDLUndefined> write(ScriptState* script_state,
+                                    ScriptValue chunk,
+                                    WritableStreamDefaultController*,
+                                    ExceptionState& exception_state) override {
+    v8::Local<v8::Value> value = chunk.V8ValueFor(script_state);
+    if (value->IsArrayBuffer() || value->IsArrayBufferView()) {
+      V8BufferSource* source = V8BufferSource::Create(
+          script_state->GetIsolate(), chunk.V8Value(), exception_state);
+      // TODO(nrosenthal): find cases where this can legitimately fail.
+      CHECK(!exception_state.HadException());
+      patch_->AppendBytes(DOMArrayPiece(source).ByteSpan());
+    } else {
+      String chunk_as_string;
+      if (value->IsSymbol() || !chunk.ToString(chunk_as_string)) {
+        auto* exception = DOMException::Create(
+            "Patch stream only accepts byte buffers or values that can be "
+            "stringified",
+            DOMException::GetErrorName(DOMExceptionCode::kDataError));
+        patch_->Terminate(ScriptValue::From(script_state, exception));
+        return ScriptPromise<IDLUndefined>::RejectWithDOMException(script_state,
+                                                                   exception);
+      }
+      patch_->Append(chunk_as_string);
+    }
+    return ToResolvedUndefinedPromise(script_state);
+  }
+
+  ScriptPromise<IDLUndefined> close(ScriptState* script_state,
+                                    ExceptionState&) override {
+    patch_->Finish();
+    return ToResolvedUndefinedPromise(script_state);
+  }
+  ScriptPromise<IDLUndefined> abort(ScriptState* script_state,
+                                    ScriptValue reason,
+                                    ExceptionState&) override {
+    patch_->Terminate(reason);
+    return ToResolvedUndefinedPromise(script_state);
+  }
+
+  Member<DOMPatchStatus> patch_;
+};
+}  // namespace
+
 // static
 PatchSupplement* PatchSupplement::FromIfExists(const Document& document) {
   return Supplement<Document>::From<PatchSupplement>(document);
@@ -64,6 +136,21 @@
   }
 }
 
+WritableStream* PatchSupplement::CreateSinglePatchStream(
+    ScriptState* script_state,
+    ContainerNode& target) {
+  DOMPatchStatus* previous = CurrentPatchFor(target);
+  if (previous) {
+    previous->Terminate(ScriptValue::From(
+        script_state,
+        DOMException::Create(
+            "Patch aborted by another patch call",
+            DOMException::GetErrorName(DOMExceptionCode::kAbortError))));
+  };
+  return WritableStream::CreateWithCountQueueingStrategy(
+      script_state, MakeGarbageCollected<SinglePatchSink>(target), 1);
+}
+
 void PatchSupplement::Trace(Visitor* visitor) const {
   visitor->Trace(patches_);
   Supplement<Document>::Trace(visitor);
diff --git a/third_party/blink/renderer/core/patching/patch_supplement.h b/third_party/blink/renderer/core/patching/patch_supplement.h
index e8d96e0..5ec44a2 100644
--- a/third_party/blink/renderer/core/patching/patch_supplement.h
+++ b/third_party/blink/renderer/core/patching/patch_supplement.h
@@ -15,6 +15,9 @@
 
 namespace blink {
 
+class ScriptState;
+class WritableStream;
+
 class PatchSupplement : public GarbageCollected<PatchSupplement>,
                         public Supplement<Document> {
  public:
@@ -30,6 +33,7 @@
   DOMPatchStatus* CurrentPatchFor(const Node&);
   void DidStart(Node&, DOMPatchStatus*);
   void DidComplete(Node&);
+  WritableStream* CreateSinglePatchStream(ScriptState*, ContainerNode&);
 
  private:
   std::optional<size_t> IndexOfPatch(const Node& target);
diff --git a/third_party/blink/renderer/core/script/module_map_test.cc b/third_party/blink/renderer/core/script/module_map_test.cc
index f687cd27..0d45637 100644
--- a/third_party/blink/renderer/core/script/module_map_test.cc
+++ b/third_party/blink/renderer/core/script/module_map_test.cc
@@ -176,10 +176,10 @@
    private:
     ResolvedModuleType ResolvedModuleTypeFromUrl() {
       const AtomicString& string_url = url_.GetString();
-      if (string_url.Find(".js") != WTF::kNotFound) {
+      if (string_url.Find(".js") != kNotFound) {
         return ResolvedModuleType::kJavaScript;
       }
-      CHECK_NE(string_url.Find(".wasm"), WTF::kNotFound);
+      CHECK_NE(string_url.Find(".wasm"), kNotFound);
       return ResolvedModuleType::kWasm;
     }
 
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc
index 7a75996..85e5f98 100644
--- a/third_party/blink/renderer/core/script/script_loader.cc
+++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -451,28 +451,6 @@
   }
 }
 
-// [Intervention, SelectiveInOrderScript, crbug.com/1356396]
-bool IsEligibleForSelectiveInOrder(const Resource& resource,
-                                   const Document& element_document) {
-  // The feature flag is checked separately.
-
-  if (!IsEligibleCommon(element_document)) {
-    return false;
-  }
-
-  // Cross-site scripts only: 1st party scripts are out of scope of the
-  // intervention.
-  if (IsSameSite(resource.Url(), element_document)) {
-    return false;
-  }
-
-  // Only script request URLs in the allowlist.
-  DEFINE_STATIC_LOCAL(
-      UrlMatcher, url_matcher,
-      (UrlMatcher(features::kSelectiveInOrderScriptAllowList.Get())));
-  return url_matcher.Match(resource.Url());
-}
-
 ScriptRunner::DelayReasons DetermineDelayReasonsToWait(
     ScriptRunner* script_runner,
     bool is_eligible_for_delay) {
@@ -765,7 +743,6 @@
       ToScriptStateForMainWorld(context_window->GetFrame());
 
   bool is_eligible_for_delay = false;
-  bool is_eligible_for_selective_in_order = false;
 
   // <spec step="31">If el has a src content attribute, then:</spec>
   if (element_->HasSourceAttribute()) {
@@ -901,8 +878,6 @@
         is_eligible_for_delay =
             IsEligibleForDelay(*resource, element_document, *element_,
                                parser_inserted_, is_in_document_write);
-        is_eligible_for_selective_in_order =
-            IsEligibleForSelectiveInOrder(*resource, element_document);
         break;
       }
       case ScriptTypeAtPrepare::kModule: {
@@ -1106,26 +1081,6 @@
   ScriptSchedulingType script_scheduling_type = GetScriptSchedulingTypePerSpec(
       element_document, parser_blocking_inline_option);
 
-  // [Intervention, SelectiveInOrderScript, crbug.com/1356396]
-  // Check for external script that
-  // should be in-order. This simply marks the parser blocking scripts as
-  // kInOrder if it's eligible. We use ScriptSchedulingType::kInOrder
-  // rather than kForceInOrder here since we don't preserve evaluation order
-  // between intervened scripts and ordinary parser-blocking/inline scripts.
-  if (is_eligible_for_selective_in_order) {
-    switch (script_scheduling_type) {
-      case ScriptSchedulingType::kParserBlocking:
-        UseCounter::Count(context_window->document()->TopDocument(),
-                          WebFeature::kSelectiveInOrderScript);
-        if (base::FeatureList::IsEnabled(features::kSelectiveInOrderScript)) {
-          script_scheduling_type = ScriptSchedulingType::kInOrder;
-        }
-        break;
-      default:
-        break;
-    }
-  }
-
   // [Intervention, ForceInOrderScript, crbug.com/1344772]
   // Check for external script that
   // should be force in-order. Not only the pending scripts that would be marked
diff --git a/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc b/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc
index 97e299d9..5190f2d1 100644
--- a/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc
+++ b/third_party/blink/renderer/core/streams/byte_stream_tee_engine.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/byte_stream_tee_engine.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/core/execution_context/agent.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -29,9 +30,15 @@
     DCHECK(branch == 0 || branch == 1);
   }
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamtee
     // This implements both pull1Algorithm and pull2Algorithm as they are
     // identical except for the index they operate on. Standard comments are
@@ -82,9 +89,15 @@
     DCHECK(branch == 0 || branch == 1);
   }
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamtee
     // This implements both cancel1Algorithm and cancel2Algorithm as they are
     // identical except for the index they operate on. Standard comments are
@@ -95,7 +108,7 @@
     //   a. Set canceled1 to true.
     engine_->canceled_[branch_] = true;
     //   b. Set reason1 to reason.
-    DCHECK_EQ(argc, 1);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     engine_->reason_[branch_].Reset(isolate, argv[0]);
     //   c. If canceled2 is true,
     const int other_branch = 1 - branch_;
@@ -272,11 +285,11 @@
     // 8. If readAgainForBranch1 is true, perform pull1Algorithm.
     if (engine_->read_again_for_branch_[0]) {
       auto* pull_algorithm = MakeGarbageCollected<PullAlgorithm>(engine_, 0);
-      pull_algorithm->Run(script_state, 0, nullptr);
+      pull_algorithm->Run(script_state, 0, {});
       // 9. Otherwise, if readAgainForBranch2 is true, perform pull2Algorithm.
     } else if (engine_->read_again_for_branch_[1]) {
       auto* pull_algorithm = MakeGarbageCollected<PullAlgorithm>(engine_, 1);
-      pull_algorithm->Run(script_state, 0, nullptr);
+      pull_algorithm->Run(script_state, 0, {});
     }
   }
 
@@ -463,11 +476,11 @@
     // 8. If readAgainForBranch1 is true, perform pull1Algorithm.
     if (engine_->read_again_for_branch_[0]) {
       auto* pull_algorithm = MakeGarbageCollected<PullAlgorithm>(engine_, 0);
-      pull_algorithm->Run(script_state, 0, nullptr);
+      pull_algorithm->Run(script_state, 0, {});
       // 9. Otherwise, if readAgainForBranch2 is true, perform pull2Algorithm.
     } else if (engine_->read_again_for_branch_[1]) {
       auto* pull_algorithm = MakeGarbageCollected<PullAlgorithm>(engine_, 1);
-      pull_algorithm->Run(script_state, 0, nullptr);
+      pull_algorithm->Run(script_state, 0, {});
     }
   }
 
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
index 1d6fdca..1325859 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations.cc
@@ -11,6 +11,7 @@
 
 #include <optional>
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_readable_stream.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h"
@@ -76,9 +77,15 @@
 
 class TrivialStreamAlgorithm final : public StreamAlgorithm {
  public:
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     return ToResolvedUndefinedPromise(script_state);
   }
 };
@@ -94,19 +101,25 @@
   // CreateAlgorithmFromUnderlyingMethod() in the standard, but it is
   // determined when the algorithm is called rather than when the algorithm is
   // created.
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // This method technically supports any number of arguments, but we only
     // call it with 0 or 1 in practice.
-    DCHECK_GE(argc, 0);
+    DCHECK_GE(spanification_suspected_redundant_argc, 0);
     auto* isolate = script_state->GetIsolate();
     // https://streams.spec.whatwg.org/#create-algorithm-from-underlying-method
     // 6.b.i. Return ! PromiseCall(method, underlyingObject, extraArgs).
     // In this class extraArgs is always empty, but there may be other arguments
     // supplied to the method.
     return PromiseCall(script_state, method_.Get(isolate), recv_.Get(isolate),
-                       argc, argv);
+                       spanification_suspected_redundant_argc, argv.data());
   }
 
   void Trace(Visitor* visitor) const override {
@@ -132,22 +145,28 @@
 
   // |argc| is equivalent to the "algoArgCount" argument to
   // CreateAlgorithmFromUnderlyingMethod() in the standard,
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_GE(argc, 0);
-    DCHECK_LE(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_GE(spanification_suspected_redundant_argc, 0);
+    DCHECK_LE(spanification_suspected_redundant_argc, 1);
     auto* isolate = script_state->GetIsolate();
     // https://streams.spec.whatwg.org/#create-algorithm-from-underlying-method
     // 6.c.
     //      i. Let fullArgs be a List consisting of arg followed by the
     //         elements of extraArgs in order.
     std::array<v8::Local<v8::Value>, 2> full_argv;
-    if (argc != 0) {
+    if (spanification_suspected_redundant_argc != 0) {
       full_argv[0] = argv[0];
     }
-    full_argv[argc] = extra_arg_.Get(isolate);
-    int full_argc = argc + 1;
+    full_argv[spanification_suspected_redundant_argc] = extra_arg_.Get(isolate);
+    int full_argc = spanification_suspected_redundant_argc + 1;
 
     //     ii. Return ! PromiseCall(method, underlyingObject, fullArgs).
     return PromiseCall(script_state, method_.Get(isolate), recv_.Get(isolate),
diff --git a/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc b/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc
index 618acbf6..a53b6679 100644
--- a/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc
+++ b/third_party/blink/renderer/core/streams/miscellaneous_operations_test.cc
@@ -8,6 +8,7 @@
 
 #include <limits>
 
+#include "base/containers/span.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
@@ -38,7 +39,7 @@
       scope.GetScriptState(), underlying_object, "pull",
       "underlyingSource.pull", EmptyExtraArg(), ASSERT_NO_EXCEPTION);
   ASSERT_TRUE(algo);
-  auto promise = algo->Run(scope.GetScriptState(), 0, nullptr);
+  auto promise = algo->Run(scope.GetScriptState(), 0, {});
   ASSERT_FALSE(promise.IsEmpty());
   ASSERT_EQ(promise.V8Promise()->State(), v8::Promise::kFulfilled);
   EXPECT_TRUE(promise.V8Promise()->Result()->IsUndefined());
@@ -56,7 +57,7 @@
       scope.GetScriptState(), underlying_object, "pull",
       "underlyingSource.pull", EmptyExtraArg(), ASSERT_NO_EXCEPTION);
   ASSERT_TRUE(algo);
-  auto promise = algo->Run(scope.GetScriptState(), 0, nullptr);
+  auto promise = algo->Run(scope.GetScriptState(), 0, {});
   ASSERT_FALSE(promise.IsEmpty());
   ASSERT_EQ(promise.V8Promise()->State(), v8::Promise::kFulfilled);
   EXPECT_TRUE(promise.V8Promise()->Result()->IsUndefined());
@@ -98,7 +99,7 @@
     const char* function_definition,
     v8::MaybeLocal<v8::Value> extra_arg = v8::MaybeLocal<v8::Value>(),
     int argc = 0,
-    v8::Local<v8::Value> argv[] = nullptr) {
+    base::span<v8::Local<v8::Value>> argv = {}) {
   String js = String("({start: ") + function_definition + "})" + '\0';
   ScriptValue underlying_value =
       EvalWithPrintingError(scope, js.Utf8().c_str());
@@ -133,7 +134,7 @@
     const char* function_definition,
     v8::MaybeLocal<v8::Value> extra_arg = v8::MaybeLocal<v8::Value>(),
     int argc = 0,
-    v8::Local<v8::Value> argv[] = nullptr) {
+    base::span<v8::Local<v8::Value>> argv = {}) {
   auto result = CreateFromFunctionAndGetResult(scope, function_definition,
                                                extra_arg, argc, argv);
   if (!result->IsBoolean()) {
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
index a8dd063..8c958ff0 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/readable_byte_stream_controller.h"
 
+#include "base/containers/span.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/clamped_math.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
@@ -583,8 +584,7 @@
   controller->pulling_ = true;
   // 6. Let pullPromise be the result of performing
   // controller.[[pullAlgorithm]].
-  auto pull_promise =
-      controller->pull_algorithm_->Run(script_state, 0, nullptr);
+  auto pull_promise = controller->pull_algorithm_->Run(script_state, 0, {});
 
   class ResolveFunction final
       : public ThenCallable<IDLUndefined, ResolveFunction> {
@@ -1679,7 +1679,8 @@
   ResetQueue(this);
   // 3. Let result be the result of performing this.[[cancelAlgorithm]], passing
   // in reason.
-  auto result = cancel_algorithm_->Run(script_state, 1, &reason);
+  auto result =
+      cancel_algorithm_->Run(script_state, 1, base::span_from_ref(reason));
   // 4. Perform ! ReadableByteStreamControllerClearAlgorithms(this).
   ClearAlgorithms(this);
   // 5. Return result.
diff --git a/third_party/blink/renderer/core/streams/readable_stream.cc b/third_party/blink/renderer/core/streams/readable_stream.cc
index aa41d8b..b50020c 100644
--- a/third_party/blink/renderer/core/streams/readable_stream.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
@@ -59,10 +60,16 @@
   explicit PullAlgorithm(UnderlyingByteSourceBase* underlying_byte_source)
       : underlying_byte_source_(underlying_byte_source) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 0);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 0);
     DCHECK(controller_);
     ScriptPromise<IDLUndefined> promise;
     if (script_state->ContextIsValid()) {
@@ -109,10 +116,16 @@
   explicit CancelAlgorithm(UnderlyingByteSourceBase* underlying_byte_source)
       : underlying_byte_source_(underlying_byte_source) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     ScriptPromise<IDLUndefined> promise;
     if (script_state->ContextIsValid()) {
       v8::TryCatch try_catch(script_state->GetIsolate());
diff --git a/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc b/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
index f3fb53e..d68fc86 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_default_controller.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
@@ -342,7 +343,8 @@
 
   // 2. Let result be the result of performing this.[[cancelAlgorithm]], passing
   //    reason.
-  auto result = cancel_algorithm_->Run(script_state, 1, &reason);
+  auto result =
+      cancel_algorithm_->Run(script_state, 1, base::span_from_ref(reason));
 
   // 3. Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).
   ClearAlgorithms(this);
@@ -429,8 +431,7 @@
 
   // 6. Let pullPromise be the result of performing
   //    controller.[[pullAlgorithm]].
-  auto pull_promise =
-      controller->pull_algorithm_->Run(script_state, 0, nullptr);
+  auto pull_promise = controller->pull_algorithm_->Run(script_state, 0, {});
 
   pull_promise.Then(script_state, controller->resolve_function_.Get(),
                     controller->reject_function_.Get());
diff --git a/third_party/blink/renderer/core/streams/stream_algorithms.h b/third_party/blink/renderer/core/streams/stream_algorithms.h
index e72e97d..16e7e30 100644
--- a/third_party/blink/renderer/core/streams/stream_algorithms.h
+++ b/third_party/blink/renderer/core/streams/stream_algorithms.h
@@ -7,6 +7,7 @@
 
 #include <optional>
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
@@ -53,9 +54,10 @@
  public:
   virtual ~StreamAlgorithm() = default;
 
-  virtual ScriptPromise<IDLUndefined> Run(ScriptState*,
-                                          int argc,
-                                          v8::Local<v8::Value> argv[]) = 0;
+  virtual ScriptPromise<IDLUndefined> Run(
+      ScriptState*,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) = 0;
 
   virtual void Trace(Visitor*) const {}
 };
diff --git a/third_party/blink/renderer/core/streams/tee_engine.cc b/third_party/blink/renderer/core/streams/tee_engine.cc
index 7c6a9f9..d5006ac 100644
--- a/third_party/blink/renderer/core/streams/tee_engine.cc
+++ b/third_party/blink/renderer/core/streams/tee_engine.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/tee_engine.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/execution_context/agent.h"
@@ -49,9 +50,15 @@
  public:
   explicit PullAlgorithm(TeeEngine* engine) : engine_(engine) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int,
-                                  v8::Local<v8::Value>[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#readable-stream-tee
     // 13. Let pullAlgorithm be the following steps:
     //   a. If reading is true,
@@ -208,7 +215,7 @@
       // 7. If readAgain is true, perform pullAlgorithm.
       if (engine_->read_again_) {
         auto* pull_algorithm = MakeGarbageCollected<PullAlgorithm>(engine_);
-        pull_algorithm->Run(script_state, 0, nullptr);
+        pull_algorithm->Run(script_state, 0, {});
       }
     }
 
@@ -225,9 +232,15 @@
     DCHECK(branch == 0 || branch == 1);
   }
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#readable-stream-tee
     // This implements both cancel1Algorithm and cancel2Algorithm as they are
     // identical except for the index they operate on. Standard comments are
@@ -238,7 +251,7 @@
 
     // a. Set canceled1 to true.
     engine_->canceled_[branch_] = true;
-    DCHECK_EQ(argc, 1);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
 
     // b. Set reason1 to reason.
     engine_->reason_[branch_].Reset(isolate, argv[0]);
diff --git a/third_party/blink/renderer/core/streams/transferable_streams.cc b/third_party/blink/renderer/core/streams/transferable_streams.cc
index b42d123b..3d1be655 100644
--- a/third_party/blink/renderer/core/streams/transferable_streams.cc
+++ b/third_party/blink/renderer/core/streams/transferable_streams.cc
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/streams/transferable_streams.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/promise_all.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
@@ -371,12 +372,18 @@
 
   // Sends the chunk to the readable side, possibly after waiting for
   // backpressure.
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable
     // 8. Let writeAlgorithm be the following steps, taking a chunk argument:
-    DCHECK_EQ(argc, 1);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     auto chunk = argv[0];
 
     // 1. If backpressurePromise is undefined, set backpressurePromise to a
@@ -471,10 +478,16 @@
       : writable_(writable) {}
 
   // Sends a close message to the readable side and closes the message port.
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 0);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 0);
 
     // https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable
     // 9. Let closeAlgorithm be the folowing steps:
@@ -514,12 +527,18 @@
       : writable_(writable) {}
 
   // Sends an abort message to the readable side and closes the message port.
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable
     // 10. Let abortAlgorithm be the following steps, taking a reason argument:
-    DCHECK_EQ(argc, 1);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     auto reason = argv[0];
 
     v8::Local<v8::Value> error;
@@ -684,10 +703,16 @@
 
   // Sends a pull message to the writable side and then waits for backpressure
   // to clear.
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 0);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 0);
     auto* isolate = script_state->GetIsolate();
 
     // https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
@@ -729,12 +754,18 @@
       : readable_(readable) {}
 
   // Sends a cancel message to the writable side and closes the message port.
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
     // https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
     // 8. Let cancelAlgorithm be the following steps, taking a reason argument:
-    DCHECK_EQ(argc, 1);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     auto reason = argv[0];
 
     v8::Local<v8::Value> error;
diff --git a/third_party/blink/renderer/core/streams/transform_stream.cc b/third_party/blink/renderer/core/streams/transform_stream.cc
index f7a4e2e0..3b49d6a 100644
--- a/third_party/blink/renderer/core/streams/transform_stream.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/transform_stream.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
@@ -31,10 +32,16 @@
   explicit FlushAlgorithm(TransformStreamTransformer* transformer)
       : transformer_(transformer) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 0);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 0);
     DCHECK(controller_);
     v8::Isolate* isolate = script_state->GetIsolate();
     auto* transformer_script_state = transformer_->GetScriptState();
@@ -82,10 +89,16 @@
   explicit TransformAlgorithm(TransformStreamTransformer* transformer)
       : transformer_(transformer) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     DCHECK(controller_);
     v8::Isolate* isolate = script_state->GetIsolate();
     auto* transformer_script_state = transformer_->GetScriptState();
@@ -310,10 +323,16 @@
   explicit DefaultSinkWriteAlgorithm(TransformStream* stream)
       : stream_(stream) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     const auto chunk = argv[0];
 
     // https://streams.spec.whatwg.org/#transform-stream-default-sink-write-algorithm
@@ -407,10 +426,16 @@
   explicit DefaultSinkAbortAlgorithm(TransformStream* stream)
       : stream_(stream) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     const auto reason = argv[0];
 
     // https://streams.spec.whatwg.org/#transform-stream-default-sink-abort-algorithm
@@ -436,21 +461,25 @@
   explicit DefaultSinkCloseAlgorithm(TransformStream* stream)
       : stream_(stream) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 0);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 0);
     // https://streams.spec.whatwg.org/#transform-stream-default-sink-close-algorithm
     // 1. Let readable be stream.[[readable]].
-
     // 2. Let controller be stream.[[transformStreamController]].
     TransformStreamDefaultController* controller =
         stream_->transform_stream_controller_;
 
     // 3. Let flushPromise be the result of performing
     //    controller.[[flushAlgorithm]].
-    auto flush_promise =
-        controller->flush_algorithm_->Run(script_state, 0, nullptr);
+    auto flush_promise = controller->flush_algorithm_->Run(script_state, 0, {});
 
     // 4. Perform ! TransformStreamDefaultControllerClearAlgorithms(controller).
     TransformStreamDefaultController::ClearAlgorithms(controller);
@@ -542,10 +571,16 @@
   explicit DefaultSourcePullAlgorithm(TransformStream* stream)
       : stream_(stream) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 0);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 0);
 
     // https://streams.spec.whatwg.org/#transform-stream-default-source-pull
     // 1. Assert: stream.[[backpressure]] is true.
@@ -578,10 +613,16 @@
   explicit DefaultSourceCancelAlgorithm(TransformStream* stream)
       : stream_(stream) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
 
     // https://streams.spec.whatwg.org/#initialize-transform-stream
     // 7. Let cancelAlgorithm be the following steps, taking a reason argument:
diff --git a/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc b/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
index e7777c7d..ef58ca4 100644
--- a/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
+++ b/third_party/blink/renderer/core/streams/transform_stream_default_controller.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/transform_stream_default_controller.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
 #include "third_party/blink/renderer/core/streams/readable_stream.h"
@@ -104,10 +105,16 @@
       TransformStreamDefaultController* controller)
       : controller_(controller) {}
 
-  ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) override {
-    DCHECK_EQ(argc, 1);
+  ScriptPromise<IDLUndefined> Run(
+      ScriptState* script_state,
+      int spanification_suspected_redundant_argc,
+      base::span<v8::Local<v8::Value>> argv) override {
+    // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+    // redundant in M143.
+    CHECK(
+        spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+    DCHECK_EQ(spanification_suspected_redundant_argc, 1);
     v8::Isolate* isolate = script_state->GetIsolate();
     v8::TryCatch try_catch(isolate);
 
@@ -366,7 +373,8 @@
   // needs to be returned to the outer scope.
   ScriptState::EscapableScope scope(script_state);
   ScriptPromise<IDLUndefined> transform_promise =
-      controller->transform_algorithm_->Run(script_state, 1, &chunk);
+      controller->transform_algorithm_->Run(script_state, 1,
+                                            base::span_from_ref(chunk));
   DCHECK(!transform_promise.IsEmpty());
 
   // 2. Return the result of transforming transformPromise ...
diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.cc b/third_party/blink/renderer/core/streams/underlying_sink_base.cc
index 6b9eb40..193e48f 100644
--- a/third_party/blink/renderer/core/streams/underlying_sink_base.cc
+++ b/third_party/blink/renderer/core/streams/underlying_sink_base.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
 #include "v8/include/v8.h"
 
@@ -32,9 +33,13 @@
 
 ScriptPromise<IDLUndefined> UnderlyingSinkWriteAlgorithm::Run(
     ScriptState* script_state,
-    int argc,
-    v8::Local<v8::Value> argv[]) {
-  DCHECK_EQ(argc, 1);
+    int spanification_suspected_redundant_argc,
+    base::span<v8::Local<v8::Value>> argv) {
+  // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+  // redundant in M143.
+  CHECK(spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+  DCHECK_EQ(spanification_suspected_redundant_argc, 1);
   v8::Isolate* isolate = script_state->GetIsolate();
   v8::TryCatch try_catch(isolate);
   auto result = sink_->write(script_state,
@@ -54,9 +59,13 @@
 
 ScriptPromise<IDLUndefined> UnderlyingSinkCloseAlgorithm::Run(
     ScriptState* script_state,
-    int argc,
-    v8::Local<v8::Value> argv[]) {
-  DCHECK_EQ(argc, 0);
+    int spanification_suspected_redundant_argc,
+    base::span<v8::Local<v8::Value>> argv) {
+  // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+  // redundant in M143.
+  CHECK(spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+  DCHECK_EQ(spanification_suspected_redundant_argc, 0);
   v8::Isolate* isolate = script_state->GetIsolate();
   v8::TryCatch try_catch(isolate);
   auto result = sink_->close(script_state, PassThroughException(isolate));
@@ -74,9 +83,13 @@
 
 ScriptPromise<IDLUndefined> UnderlyingSinkAbortAlgorithm::Run(
     ScriptState* script_state,
-    int argc,
-    v8::Local<v8::Value> argv[]) {
-  DCHECK_EQ(argc, 1);
+    int spanification_suspected_redundant_argc,
+    base::span<v8::Local<v8::Value>> argv) {
+  // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+  // redundant in M143.
+  CHECK(spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+  DCHECK_EQ(spanification_suspected_redundant_argc, 1);
   v8::Isolate* isolate = script_state->GetIsolate();
   v8::TryCatch try_catch(isolate);
   auto result = sink_->abort(script_state,
diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.h b/third_party/blink/renderer/core/streams/underlying_sink_base.h
index d1a07f7..60f478d 100644
--- a/third_party/blink/renderer/core/streams/underlying_sink_base.h
+++ b/third_party/blink/renderer/core/streams/underlying_sink_base.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_UNDERLYING_SINK_BASE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_UNDERLYING_SINK_BASE_H_
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -83,8 +84,8 @@
       : sink_(sink) {}
 
   ScriptPromise<IDLUndefined> Run(ScriptState*,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) final;
+                                  int spanification_suspected_redundant_argc,
+                                  base::span<v8::Local<v8::Value>> argv) final;
   void Trace(Visitor* visitor) const final;
 
  private:
@@ -97,8 +98,8 @@
       : sink_(sink) {}
 
   ScriptPromise<IDLUndefined> Run(ScriptState*,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) final;
+                                  int spanification_suspected_redundant_argc,
+                                  base::span<v8::Local<v8::Value>> argv) final;
   void Trace(Visitor* visitor) const final;
 
  private:
@@ -111,8 +112,8 @@
       : sink_(sink) {}
 
   ScriptPromise<IDLUndefined> Run(ScriptState*,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) final;
+                                  int spanification_suspected_redundant_argc,
+                                  base::span<v8::Local<v8::Value>> argv) final;
   void Trace(Visitor* visitor) const final;
 
  private:
diff --git a/third_party/blink/renderer/core/streams/underlying_source_base.cc b/third_party/blink/renderer/core/streams/underlying_source_base.cc
index cdfa78c..dcc31e01 100644
--- a/third_party/blink/renderer/core/streams/underlying_source_base.cc
+++ b/third_party/blink/renderer/core/streams/underlying_source_base.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/underlying_source_base.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_default_controller.h"
@@ -83,9 +84,13 @@
 
 ScriptPromise<IDLUndefined> UnderlyingPullAlgorithm::Run(
     ScriptState* script_state,
-    int argc,
-    v8::Local<v8::Value> argv[]) {
-  DCHECK_EQ(argc, 0);
+    int spanification_suspected_redundant_argc,
+    base::span<v8::Local<v8::Value>> argv) {
+  // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+  // redundant in M143.
+  CHECK(spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
+  DCHECK_EQ(spanification_suspected_redundant_argc, 0);
   return source_->Pull(script_state,
                        PassThroughException(script_state->GetIsolate()));
 }
@@ -97,11 +102,16 @@
 
 ScriptPromise<IDLUndefined> UnderlyingCancelAlgorithm::Run(
     ScriptState* script_state,
-    int argc,
-    v8::Local<v8::Value> argv[]) {
+    int spanification_suspected_redundant_argc,
+    base::span<v8::Local<v8::Value>> argv) {
+  // TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
+  // redundant in M143.
+  CHECK(spanification_suspected_redundant_argc == static_cast<int>(argv.size()),
+        base::NotFatalUntil::M143);
   v8::Isolate* isolate = script_state->GetIsolate();
-  v8::Local<v8::Value> reason =
-      argc > 0 ? argv[0] : v8::Undefined(isolate).As<v8::Value>();
+  v8::Local<v8::Value> reason = spanification_suspected_redundant_argc > 0
+                                    ? argv[0]
+                                    : v8::Undefined(isolate).As<v8::Value>();
   return source_->CancelWrapper(
       script_state, ScriptValue(isolate, reason),
       PassThroughException(script_state->GetIsolate()));
diff --git a/third_party/blink/renderer/core/streams/underlying_source_base.h b/third_party/blink/renderer/core/streams/underlying_source_base.h
index 96a48523..abefb42 100644
--- a/third_party/blink/renderer/core/streams/underlying_source_base.h
+++ b/third_party/blink/renderer/core/streams/underlying_source_base.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_UNDERLYING_SOURCE_BASE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_UNDERLYING_SOURCE_BASE_H_
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -78,8 +79,8 @@
       : source_(source) {}
 
   ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) final;
+                                  int spanification_suspected_redundant_argc,
+                                  base::span<v8::Local<v8::Value>> argv) final;
   void Trace(Visitor* visitor) const final;
 
  private:
@@ -92,8 +93,8 @@
       : source_(source) {}
 
   ScriptPromise<IDLUndefined> Run(ScriptState* script_state,
-                                  int argc,
-                                  v8::Local<v8::Value> argv[]) final;
+                                  int spanification_suspected_redundant_argc,
+                                  base::span<v8::Local<v8::Value>> argv) final;
   void Trace(Visitor* visitor) const final;
 
  private:
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
index 72be679..15cc0a66c 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
 
+#include "base/containers/span.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream_default_controller.h"
@@ -148,7 +149,8 @@
   // https://streams.spec.whatwg.org/#ws-default-controller-private-abort
   //  1. Let result be the result of performing this.[[abortAlgorithm]], passing
   //     reason.
-  const auto result = abort_algorithm_->Run(script_state, 1, &reason);
+  const auto result =
+      abort_algorithm_->Run(script_state, 1, base::span_from_ref(reason));
 
   //  2. Perform ! WritableStreamDefaultControllerClearAlgorithms(this).
   ClearAlgorithms(this);
@@ -589,7 +591,7 @@
   //  5. Let sinkClosePromise be the result of performing
   //     controller.[[closeAlgorithm]].
   const auto sinkClosePromise =
-      controller->close_algorithm_->Run(script_state, 0, nullptr);
+      controller->close_algorithm_->Run(script_state, 0, {});
 
   //  6. Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
   ClearAlgorithms(controller);
@@ -653,8 +655,8 @@
 
   //  3. Let sinkWritePromise be the result of performing
   //     controller.[[writeAlgorithm]], passing in chunk.
-  const auto sinkWritePromise =
-      controller->write_algorithm_->Run(script_state, 1, &chunk);
+  const auto sinkWritePromise = controller->write_algorithm_->Run(
+      script_state, 1, base::span_from_ref(chunk));
 
   sinkWritePromise.Then(script_state, controller->resolve_function_.Get(),
                         controller->reject_function_.Get());
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 335cc7c..871e859 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -628,10 +628,6 @@
     }
     return 0;
   }
-  bool HasAutoLineClamp() const {
-    return RuntimeEnabledFeatures::CSSLineClampEnabled() &&
-           IsEffectiveContinueCollapse() && !MaxLines();
-  }
   bool IsEffectiveContinueCollapse() const {
     DCHECK(RuntimeEnabledFeatures::CSSLineClampEnabled());
     switch (Continue()) {
diff --git a/third_party/blink/renderer/core/timing/navigation_id_generator.cc b/third_party/blink/renderer/core/timing/navigation_id_generator.cc
index 2ee3b137..a3aef1d 100644
--- a/third_party/blink/renderer/core/timing/navigation_id_generator.cc
+++ b/third_party/blink/renderer/core/timing/navigation_id_generator.cc
@@ -33,7 +33,7 @@
 }
 
 void NavigationIdGenerator::IncrementNavigationId() {
-  CHECK_NE(navigation_id_, kNavigationIdDefaultValue);
+  CHECK_NE(navigation_id_, kNavigationIdAbsentValue);
   // Check for overflow, and reset the navigation id if it happens.
   if (navigation_id_ > kMaxNavigationId - kNavigationIdIncrement) {
     ResetNavigationId();
diff --git a/third_party/blink/renderer/core/timing/navigation_id_generator.h b/third_party/blink/renderer/core/timing/navigation_id_generator.h
index 05a6d95..62e22a29 100644
--- a/third_party/blink/renderer/core/timing/navigation_id_generator.h
+++ b/third_party/blink/renderer/core/timing/navigation_id_generator.h
@@ -6,10 +6,13 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_NAVIGATION_ID_GENERATOR_H_
 
 #include "base/gtest_prod_util.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "third_party/blink/renderer/core/core_export.h"
 
 namespace blink {
+// The value 0 indicates the absence of a navigation id.
+// It's used for when there's no navigation id, e.g. in service workers.
+inline constexpr uint32_t kNavigationIdAbsentValue = 0;
 
 // Implements the navigationId as specified in
 // https://w3c.github.io/performance-timeline/:
@@ -41,7 +44,7 @@
   void ResetNavigationId();
 
   FRIEND_TEST_ALL_PREFIXES(NavigationIdGeneratorTest, SoftNavigationsOverflow);
-  uint32_t navigation_id_ = kNavigationIdDefaultValue;
+  uint32_t navigation_id_ = kNavigationIdAbsentValue;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/timing/navigation_id_generator_test.cc b/third_party/blink/renderer/core/timing/navigation_id_generator_test.cc
index 71066c8..478a809c 100644
--- a/third_party/blink/renderer/core/timing/navigation_id_generator_test.cc
+++ b/third_party/blink/renderer/core/timing/navigation_id_generator_test.cc
@@ -14,7 +14,7 @@
 TEST(NavigationIdGeneratorTest, InitialValueIsRandomForHardNavigations) {
   NavigationIdGenerator generator;
   uint32_t id = generator.NavigationId();
-  EXPECT_NE(id, kNavigationIdDefaultValue);
+  EXPECT_NE(id, kNavigationIdAbsentValue);
   EXPECT_GE(id, kMinNavigationId);
   EXPECT_LE(id, kMaxNavigationIdForReset);
 }
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index 7e2cb71..7d8c99e 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -35,14 +35,15 @@
 #include "base/functional/callback_forward.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/loader/frame_loader_types.h"
+#include "third_party/blink/renderer/core/timing/navigation_id_generator.h"
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 #include "third_party/blink/renderer/core/timing/performance_paint_timing.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_deque.h"
@@ -194,7 +195,7 @@
                                   kResourcetimingbufferfull)
 
   virtual uint32_t NavigationId() const {
-    return blink::kNavigationIdDefaultValue;
+    return blink::kNavigationIdAbsentValue;
   }
 
   void AddLongTaskTiming(base::TimeTicks start_time,
diff --git a/third_party/blink/renderer/core/timing/performance_entry.cc b/third_party/blink/renderer/core/timing/performance_entry.cc
index f3105466..5a9c2e0f 100644
--- a/third_party/blink/renderer/core/timing/performance_entry.cc
+++ b/third_party/blink/renderer/core/timing/performance_entry.cc
@@ -31,7 +31,6 @@
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 
 #include "base/atomic_sequence_num.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
 #include "third_party/blink/public/mojom/timing/performance_mark_or_measure.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
diff --git a/third_party/blink/renderer/core/timing/responsiveness_metrics.cc b/third_party/blink/renderer/core/timing/responsiveness_metrics.cc
index 783eb1e..9acd5e8 100644
--- a/third_party/blink/renderer/core/timing/responsiveness_metrics.cc
+++ b/third_party/blink/renderer/core/timing/responsiveness_metrics.cc
@@ -114,7 +114,7 @@
   base::TimeDelta total_duration =
       timestamps[0].end_time - timestamps[0].creation_time;
   base::TimeTicks current_end_time = timestamps[0].end_time;
-  for (WTF::wtf_size_t i = 1; i < timestamps.size(); ++i) {
+  for (wtf_size_t i = 1; i < timestamps.size(); ++i) {
     total_duration += timestamps[i].end_time - timestamps[i].creation_time;
     if (timestamps[i].creation_time < current_end_time) {
       total_duration -= std::min(current_end_time, timestamps[i].end_time) -
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_context.h b/third_party/blink/renderer/core/timing/soft_navigation_context.h
index bec79370..66db508 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_context.h
+++ b/third_party/blink/renderer/core/timing/soft_navigation_context.h
@@ -9,9 +9,10 @@
 
 #include "base/time/time.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/performance/performance_timeline_constants.h"
+#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/timing/navigation_id_generator.h"
 #include "third_party/blink/renderer/core/timing/performance_entry.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -39,7 +40,7 @@
   }
 
   bool HasNavigationId() const {
-    return navigation_id_ != kNavigationIdDefaultValue;
+    return navigation_id_ != kNavigationIdAbsentValue;
   }
   uint32_t NavigationId() const { return navigation_id_; }
   void SetNavigationId(uint32_t navigation_id) {
@@ -116,7 +117,7 @@
   // largest value and can be used to identify the most recent context.
   const uint64_t context_id_ = ++last_context_id_;
 
-  uint32_t navigation_id_ = kNavigationIdDefaultValue;
+  uint32_t navigation_id_ = kNavigationIdAbsentValue;
   const features::SoftNavigationHeuristicsMode paint_attribution_mode_;
 
   base::TimeTicks user_interaction_timestamp_;
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
index 9a630d8..278737d3 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -538,7 +538,7 @@
   CHECK(EnsureContextForCurrentWindow(context));
 
   if (LocalFrameClient* frame_client = frame->Client()) {
-    blink::SoftNavigationMetrics metrics = {
+    blink::SoftNavigationMetricsForReporting metrics = {
         .count = soft_navigation_count_,
         .start_time = loader->GetTiming().MonotonicTimeToPseudoWallTime(
             context->UserInteractionTimestamp()),
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_type_set.cc b/third_party/blink/renderer/core/view_transition/view_transition_type_set.cc
index 951e900..3f3decd 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_type_set.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_type_set.cc
@@ -114,7 +114,7 @@
                                              const String& value,
                                              ExceptionState&) {
   wtf_size_t index = types_.Find(value);
-  if (index == WTF::kNotFound) {
+  if (index == kNotFound) {
     return false;
   }
   types_.EraseAt(index);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index d6f9c62a..08ae5991 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -2878,7 +2878,7 @@
   if (const LayoutText* layout_text = DynamicTo<LayoutText>(layout_object)) {
     const ComputedStyle& style = layout_object->StyleRef();
     if (layout_text->HasNonCollapsedText() && style.ShouldPreserveBreaks() &&
-        layout_text->PlainText().find('\n') != WTF::kNotFound) {
+        layout_text->PlainText().find('\n') != kNotFound) {
       return true;
     }
   }
diff --git a/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group.cc b/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group.cc
index aab29bd..99db668 100644
--- a/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group.cc
+++ b/third_party/blink/renderer/modules/ad_auction/validate_blink_interest_group.cc
@@ -336,7 +336,7 @@
   }
 
   if (group.ads) {
-    std::optional<WTF::wtf_size_t>
+    std::optional<wtf_size_t>
         selectable_buyer_and_seller_reporting_ids_hard_limit;
     if (base::FeatureList::IsEnabled(
             features::kFledgeLimitSelectableBuyerAndSellerReportingIds) &&
@@ -346,7 +346,7 @@
           features::kFledgeSelectableBuyerAndSellerReportingIdsHardLimit.Get();
     }
 
-    for (WTF::wtf_size_t i = 0; i < group.ads.value().size(); ++i) {
+    for (wtf_size_t i = 0; i < group.ads.value().size(); ++i) {
       const KURL& render_url = KURL(group.ads.value()[i]->render_url);
       if (!IsUrlAllowedForRenderUrls(render_url)) {
         error_field_name = String::Format("ads[%u].renderURL", i);
@@ -402,8 +402,7 @@
               mojom::blink::kMaxAllowedReportingOrigins);
           return false;
         }
-        for (WTF::wtf_size_t j = 0; j < allowed_reporting_origins->size();
-             ++j) {
+        for (wtf_size_t j = 0; j < allowed_reporting_origins->size(); ++j) {
           if (allowed_reporting_origins.value()[j]->Protocol() !=
               url::kHttpsScheme) {
             error_field_name =
@@ -419,7 +418,7 @@
   }
 
   if (group.ad_components) {
-    for (WTF::wtf_size_t i = 0; i < group.ad_components.value().size(); ++i) {
+    for (wtf_size_t i = 0; i < group.ad_components.value().size(); ++i) {
       const KURL& render_url = KURL(group.ad_components.value()[i]->render_url);
       if (!IsUrlAllowedForRenderUrls(render_url)) {
         error_field_name = String::Format("adComponents[%u].renderURL", i);
@@ -583,9 +582,9 @@
           0) {
     return true;
   }
-  WTF::wtf_size_t selectable_buyer_and_seller_reporting_ids_soft_limit =
+  wtf_size_t selectable_buyer_and_seller_reporting_ids_soft_limit =
       features::kFledgeSelectableBuyerAndSellerReportingIdsSoftLimit.Get();
-  for (WTF::wtf_size_t i = 0; i < group.ads.value().size(); ++i) {
+  for (wtf_size_t i = 0; i < group.ads.value().size(); ++i) {
     if (group.ads.value()[i]->selectable_buyer_and_seller_reporting_ids &&
         group.ads.value()[i]
                 ->selectable_buyer_and_seller_reporting_ids->size() >
diff --git a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
index 0873efc7..752041b8 100644
--- a/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
+++ b/third_party/blink/renderer/modules/cache_storage/inspector_cache_storage_agent.cc
@@ -76,7 +76,7 @@
 String BuildCacheId(const String& storage_key,
                     const std::optional<String>& storage_bucket_name,
                     const String& cache_name) {
-  DCHECK(storage_key.find('|') == WTF::kNotFound);
+  DCHECK(storage_key.find('|') == kNotFound);
   StringBuilder id;
   id.Append(storage_key);
   if (storage_bucket_name.has_value()) {
@@ -262,7 +262,7 @@
       for (auto& request : old_requests) {
         String urlPath(request->url.GetPath().ToString());
         if (urlPath.DeprecatedFindIgnoringCase(params_.path_filter) ==
-            WTF::kNotFound) {
+            kNotFound) {
           continue;
         }
         requests.push_back(std::move(request));
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index c2290dc3..b0167b0e 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -669,9 +669,6 @@
 void BaseRenderingContext2D::PutByteArray(const SkPixmap& source,
                                           const gfx::Rect& source_rect,
                                           const gfx::Vector2d& dest_offset) {
-  if (!IsCanvas2DBufferValid())
-    return;
-
   DCHECK(gfx::Rect(source.width(), source.height()).Contains(source_rect));
   int dest_x = dest_offset.x() + source_rect.x();
   DCHECK_GE(dest_x, 0);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
index 68b4787..c15a7d1 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -273,7 +273,6 @@
   void TryRestoreContextEvent(TimerBase*);
   void RestoreFromInvalidSizeIfNeeded() override;
 
-  virtual CanvasResourceProvider* GetOrCreateCanvas2DResourceProvider() = 0;
   virtual std::unique_ptr<CanvasResourceProvider>
       ReplaceResourceProviderForCanvas2D(
           std::unique_ptr<CanvasResourceProvider>) = 0;
@@ -306,7 +305,6 @@
   void PutByteArray(const SkPixmap& source,
                     const gfx::Rect& source_rect,
                     const gfx::Vector2d& dest_offset);
-  virtual bool IsCanvas2DBufferValid() { NOTREACHED(); }
 
   void WillUseCurrentFont() const;
 
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_recorder_context.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_recorder_context.cc
index cbe9ef9..99264b1 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_recorder_context.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_2d_recorder_context.cc
@@ -762,8 +762,7 @@
 void Canvas2DRecorderContext::ValidateStateStackImpl(
     const cc::PaintCanvas* canvas) const {
   DCHECK_GE(state_stack_.size(), 1u);
-  DCHECK_GT(state_stack_.size(),
-            base::checked_cast<WTF::wtf_size_t>(layer_count_));
+  DCHECK_GT(state_stack_.size(), base::checked_cast<wtf_size_t>(layer_count_));
 
   using SaveType = CanvasRenderingContext2DState::SaveType;
   DCHECK_EQ(state_stack_[0]->GetSaveType(), SaveType::kInitial);
@@ -803,7 +802,7 @@
 
       // The state stack depth should match the number of saves in the
       // recording (taking in to account that some layers require two saves).
-      DCHECK_EQ(base::checked_cast<WTF::wtf_size_t>(main_saves + layer_saves),
+      DCHECK_EQ(base::checked_cast<wtf_size_t>(main_saves + layer_saves),
                 state_stack_.size() + extra_layer_saves);
     }
   }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
index 6ee17898..a9c6358a 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc
@@ -273,14 +273,14 @@
                                            size_t row_bytes,
                                            int x,
                                            int y) {
-  DCHECK(IsCanvas2DBufferValid());
+  if (!resource_provider_ || !IsCanvas2DResourceValid()) {
+    return false;
+  }
+
   CanvasRenderingContextHost* host = Host();
   CHECK(host);
 
-  CanvasResourceProvider* provider = GetOrCreateCanvas2DResourceProvider();
-  if (provider == nullptr) {
-    return false;
-  }
+  CanvasResourceProvider* provider = resource_provider_.get();
 
   if (x <= 0 && y <= 0 && x + orig_info.width() >= host->Size().width() &&
       y + orig_info.height() >= host->Size().height()) {
@@ -653,15 +653,6 @@
     return true;
   }
 
-  if (isContextLost()) {
-    return false;
-  }
-
-  if (GetResourceProviderForCanvas2D() &&
-      !GetResourceProviderForCanvas2D()->IsValid()) {
-    return false;
-  }
-
   return !!GetOrCreateCanvas2DResourceProvider();
 }
 
@@ -1132,13 +1123,6 @@
   return canvas()->ShouldDisableAccelerationBecauseOfReadback();
 }
 
-bool CanvasRenderingContext2D::IsCanvas2DBufferValid() {
-  if (IsPaintable()) {
-    return IsCanvas2DResourceValid();
-  }
-  return false;
-}
-
 void CanvasRenderingContext2D::ColorSchemeMayHaveChanged() {
   SetColorScheme(GetColorSchemeFromCanvas(canvas()));
 }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 707c40a..901f04d 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -353,7 +353,6 @@
   void Stop() final;
 
   cc::Layer* CcLayer() const override;
-  bool IsCanvas2DBufferValid() override;
 
   void ColorSchemeMayHaveChanged() override;
 
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context.cc
index 33dcc0e..87b9046 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context.cc
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context.cc
@@ -222,9 +222,8 @@
 }
 
 bool ImageBitmapRenderingContext::IsAccelerated() const {
-  auto* resource_provider = resource_provider_for_offscreen_canvas_.get();
-  return resource_provider ? resource_provider->IsAccelerated()
-                           : Host()->ShouldTryToUseGpuRaster();
+  // This method is not supported for ImageBitmap and should not be called.
+  NOTREACHED();
 }
 
 bool ImageBitmapRenderingContext::PushFrame() {
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
index 7d171be..0397406 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@@ -453,7 +453,9 @@
     size_t row_bytes,
     int x,
     int y) {
-  DCHECK(IsCanvas2DBufferValid());
+  if (!resource_provider_ || !resource_provider_->IsValid()) {
+    return false;
+  }
 
   resource_provider_->FlushCanvas(FlushReason::kWritePixels);
 
@@ -491,12 +493,6 @@
   return true;
 }
 
-bool OffscreenCanvasRenderingContext2D::IsCanvas2DBufferValid() {
-  if (IsPaintable())
-    return resource_provider_->IsValid();
-  return false;
-}
-
 std::optional<cc::PaintRecord> OffscreenCanvasRenderingContext2D::FlushCanvas(
     FlushReason reason) {
   return resource_provider_ ? resource_provider_->FlushCanvas(reason)
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
index 6ab0ede..06ca89c3 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -161,7 +161,6 @@
   void FinalizeFrame(FlushReason) final;
 
   bool IsPaintable() const final;
-  bool IsCanvas2DBufferValid() override;
 
   scoped_refptr<CanvasResource> ProduceCanvasResource(FlushReason);
 
diff --git a/third_party/blink/renderer/modules/eventsource/event_source_parser.cc b/third_party/blink/renderer/modules/eventsource/event_source_parser.cc
index 6df75c9..a303e3b3 100644
--- a/third_party/blink/renderer/modules/eventsource/event_source_parser.cc
+++ b/third_party/blink/renderer/modules/eventsource/event_source_parser.cc
@@ -78,7 +78,7 @@
   }
   wtf_size_t field_name_end = line_.Find(':');
   wtf_size_t field_value_start;
-  if (field_name_end == WTF::kNotFound) {
+  if (field_name_end == kNotFound) {
     field_name_end = line_.size();
     field_value_start = field_name_end;
   } else {
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
index aeaa6a2..244ed29 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.cc
@@ -303,17 +303,17 @@
 }
 
 void FileSystemDirectoryHandle::QueryPermissionImpl(
-    bool writable,
+    mojom::blink::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
   if (!mojo_ptr_.is_bound()) {
     std::move(callback).Run(mojom::blink::PermissionStatus::DENIED);
     return;
   }
-  mojo_ptr_->GetPermissionStatus(writable, std::move(callback));
+  mojo_ptr_->GetPermissionStatus(mode, std::move(callback));
 }
 
 void FileSystemDirectoryHandle::RequestPermissionImpl(
-    bool writable,
+    mojom::blink::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                             mojom::blink::PermissionStatus)> callback) {
   if (!mojo_ptr_.is_bound()) {
@@ -325,7 +325,7 @@
     return;
   }
 
-  mojo_ptr_->RequestPermission(writable, std::move(callback));
+  mojo_ptr_->RequestPermission(mode, std::move(callback));
 }
 
 void FileSystemDirectoryHandle::MoveImpl(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
index b47153f..bf35a54 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_directory_handle.h
@@ -7,6 +7,7 @@
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/async_iterable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_async_iterator_file_system_directory_handle.h"
@@ -66,10 +67,10 @@
   class IterationSource;
 
   void QueryPermissionImpl(
-      bool writable,
+      mojom::blink::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(mojom::blink::PermissionStatus)>) override;
   void RequestPermissionImpl(
-      bool writable,
+      mojom::blink::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                               mojom::blink::PermissionStatus)>) override;
   void MoveImpl(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
index 96c204c..ae95803 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.cc
@@ -279,17 +279,17 @@
 }
 
 void FileSystemFileHandle::QueryPermissionImpl(
-    bool writable,
+    mojom::blink::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(mojom::blink::PermissionStatus)> callback) {
   if (!mojo_ptr_.is_bound()) {
     std::move(callback).Run(mojom::blink::PermissionStatus::DENIED);
     return;
   }
-  mojo_ptr_->GetPermissionStatus(writable, std::move(callback));
+  mojo_ptr_->GetPermissionStatus(mode, std::move(callback));
 }
 
 void FileSystemFileHandle::RequestPermissionImpl(
-    bool writable,
+    mojom::blink::FileSystemAccessPermissionMode mode,
     base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                             mojom::blink::PermissionStatus)> callback) {
   if (!mojo_ptr_.is_bound()) {
@@ -301,7 +301,7 @@
     return;
   }
 
-  mojo_ptr_->RequestPermission(writable, std::move(callback));
+  mojo_ptr_->RequestPermission(mode, std::move(callback));
 }
 
 void FileSystemFileHandle::MoveImpl(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
index 5c382db7e..71c9fa10 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_file_handle.h
@@ -7,6 +7,7 @@
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_file_handle.mojom-blink.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/modules/file_system_access/file_system_handle.h"
 #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
@@ -57,10 +58,10 @@
 
  private:
   void QueryPermissionImpl(
-      bool writable,
+      mojom::blink::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(mojom::blink::PermissionStatus)>) override;
   void RequestPermissionImpl(
-      bool writable,
+      mojom::blink::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                               mojom::blink::PermissionStatus)>) override;
   void MoveImpl(
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc b/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
index ce8065e..1e3b9a6 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_handle.cc
@@ -20,6 +20,23 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
+namespace {
+
+mojom::blink::FileSystemAccessPermissionMode GetPermissionModeForDescriptor(
+    const FileSystemHandlePermissionDescriptor* descriptor) {
+  CHECK(descriptor);
+  switch (descriptor->mode().AsEnum()) {
+    case V8FileSystemPermissionMode::Enum::kRead:
+      return mojom::blink::FileSystemAccessPermissionMode::kRead;
+    case V8FileSystemPermissionMode::Enum::kReadwrite:
+      return mojom::blink::FileSystemAccessPermissionMode::kReadWrite;
+      // TODO(crbug.com/40276567): Support kWrite permission mode;
+  };
+  NOTREACHED();
+}
+
+}  // namespace
+
 using mojom::blink::FileSystemAccessEntryPtr;
 using mojom::blink::FileSystemAccessErrorPtr;
 
@@ -47,17 +64,16 @@
           script_state);
   auto result = resolver->Promise();
 
-  QueryPermissionImpl(
-      descriptor->mode() == V8FileSystemPermissionMode::Enum::kReadwrite,
-      WTF::BindOnce(
-          [](FileSystemHandle* handle,
-             ScriptPromiseResolver<V8PermissionState>* resolver,
-             mojom::blink::PermissionStatus result) {
-            // Keep `this` alive so the handle will not be garbage-collected
-            // before the promise is resolved.
-            resolver->Resolve(ToV8PermissionState(result));
-          },
-          WrapPersistent(this), WrapPersistent(resolver)));
+  QueryPermissionImpl(GetPermissionModeForDescriptor(descriptor),
+                      WTF::BindOnce(
+                          [](FileSystemHandle* handle,
+                             ScriptPromiseResolver<V8PermissionState>* resolver,
+                             mojom::blink::PermissionStatus result) {
+                            // Keep `this` alive so the handle will not be
+                            // garbage-collected before the promise is resolved.
+                            resolver->Resolve(ToV8PermissionState(result));
+                          },
+                          WrapPersistent(this), WrapPersistent(resolver)));
 
   return result;
 }
@@ -72,7 +88,7 @@
   auto result = resolver->Promise();
 
   RequestPermissionImpl(
-      descriptor->mode() == V8FileSystemPermissionMode::Enum::kReadwrite,
+      GetPermissionModeForDescriptor(descriptor),
       WTF::BindOnce(
           [](FileSystemHandle*,
              ScriptPromiseResolver<V8PermissionState>* resolver,
diff --git a/third_party/blink/renderer/modules/file_system_access/file_system_handle.h b/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
index 0bfbf85..c4e5fb4 100644
--- a/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
+++ b/third_party/blink/renderer/modules/file_system_access/file_system_handle.h
@@ -9,6 +9,7 @@
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_cloud_identifier.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_directory_handle.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_error.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/file_system_access/file_system_access_permission_mode.mojom-blink.h"
 #include "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom-blink-forward.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
@@ -86,10 +87,10 @@
 
  private:
   virtual void QueryPermissionImpl(
-      bool writable,
+      mojom::blink::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(mojom::blink::PermissionStatus)>) = 0;
   virtual void RequestPermissionImpl(
-      bool writable,
+      mojom::blink::FileSystemAccessPermissionMode mode,
       base::OnceCallback<void(mojom::blink::FileSystemAccessErrorPtr,
                               mojom::blink::PermissionStatus)>) = 0;
   virtual void MoveImpl(
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_path.cc b/third_party/blink/renderer/modules/filesystem/dom_file_path.cc
index 3415caf..dea8d94 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_file_path.cc
+++ b/third_party/blink/renderer/modules/filesystem/dom_file_path.cc
@@ -113,13 +113,15 @@
     return true;
 
   // Embedded NULs are not allowed.
-  if (path.find(static_cast<UChar>(0)) != WTF::kNotFound)
+  if (path.find(static_cast<UChar>(0)) != kNotFound) {
     return false;
+  }
 
   // While not [yet] restricted by the spec, '\\' complicates implementation for
   // Chromium.
-  if (path.find('\\') != WTF::kNotFound)
+  if (path.find('\\') != kNotFound) {
     return false;
+  }
 
   // This method is only called on fully-evaluated absolute paths. Any sign of
   // ".." or "." is likely an attempt to break out of the sandbox.
diff --git a/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc b/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
index a005937..82c4f5d 100644
--- a/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
+++ b/third_party/blink/renderer/modules/indexeddb/indexed_db_blink_mojom_traits.cc
@@ -38,7 +38,7 @@
       object_stores;
   data.GetObjectStoresDataView(&object_stores);
   out->object_stores.ReserveCapacityForSize(
-      base::checked_cast<wtf_size_t>(object_stores.size()));
+      base::checked_cast<blink::wtf_size_t>(object_stores.size()));
   for (size_t i = 0; i < object_stores.size(); ++i) {
     const int64_t key = object_stores.keys()[i];
     scoped_refptr<blink::IDBObjectStoreMetadata> object_store;
@@ -283,7 +283,7 @@
       const auto& array = key_path.Array();
       blink::Vector<blink::String> result;
       result.ReserveInitialCapacity(
-          base::checked_cast<wtf_size_t>(array.size()));
+          base::checked_cast<blink::wtf_size_t>(array.size()));
       for (const auto& item : array)
         result.push_back(item);
       return blink::mojom::blink::IDBKeyPathData::NewStringArray(
@@ -347,7 +347,7 @@
   MapDataView<int64_t, blink::mojom::IDBIndexMetadataDataView> indexes;
   data.GetIndexesDataView(&indexes);
   value->indexes.ReserveCapacityForSize(
-      base::checked_cast<wtf_size_t>(indexes.size()));
+      base::checked_cast<blink::wtf_size_t>(indexes.size()));
   for (size_t i = 0; i < indexes.size(); ++i) {
     const int64_t key = indexes.keys()[i];
     scoped_refptr<blink::IDBIndexMetadata> index;
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index b87e3c5..ec83fa7a 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -259,7 +259,7 @@
   if (base_url.IsStandard() && !IsAbsolutePathname(pathname)) {
     String base_path = EscapePatternString(base_url.GetPath());
     auto slash_index = base_path.ReverseFind('/');
-    if (slash_index != WTF::kNotFound) {
+    if (slash_index != kNotFound) {
       // Extract the base_url path up to and including the last slash. Append
       // the relative pathname to it.
       base_path.Truncate(slash_index + 1);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
index 04446a8..87754e6 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_audio_test.cc
@@ -267,8 +267,7 @@
     ProcessingType expected_type = ProcessingType::kUnprocessed;
     const auto& properties = result.audio_processing_properties();
     bool properties_value = false;
-    for (WTF::wtf_size_t i = 0; i < GetAudioProcessingProperties().size();
-         ++i) {
+    for (wtf_size_t i = 0; i < GetAudioProcessingProperties().size(); ++i) {
       properties_value |= properties.*GetAudioProcessingProperties()[i];
     }
 
@@ -568,7 +567,7 @@
           accessor == kFactoryAccessors[1]) {
         continue;
       }
-      for (WTF::wtf_size_t i = 0; i < kMainSettings.size(); ++i) {
+      for (wtf_size_t i = 0; i < kMainSettings.size(); ++i) {
         for (bool value : kBoolValues) {
           ResetFactory();
           (((constraint_factory_.*accessor)().*kMainBoolConstraints[i]).*
@@ -600,8 +599,7 @@
           accessor == kFactoryAccessors[1]) {
         continue;
       }
-      for (WTF::wtf_size_t i = 0; i < GetAudioProcessingProperties().size();
-           ++i) {
+      for (wtf_size_t i = 0; i < GetAudioProcessingProperties().size(); ++i) {
         for (bool value : kBoolValues) {
           ResetFactory();
           (((constraint_factory_.*accessor)().*kAudioProcessingConstraints[i]).*
@@ -1372,8 +1370,7 @@
       auto set_bool_function = kBoolSetFunctions[function_idx];
       auto set_bool_or_string_function =
           kBoolOrStringSetBooleanFunctions[function_idx];
-      for (WTF::wtf_size_t i = 0; i < GetAudioProcessingProperties().size();
-           ++i) {
+      for (wtf_size_t i = 0; i < GetAudioProcessingProperties().size(); ++i) {
         ResetFactory();
         ((constraint_factory_.*accessor)().echo_cancellation.*
          set_bool_or_string_function)(false);
@@ -1386,8 +1383,7 @@
                   result.audio_processing_properties().echo_cancellation_mode);
         EXPECT_TRUE(result.audio_processing_properties().*
                     GetAudioProcessingProperties()[i]);
-        for (WTF::wtf_size_t j = 0; j < GetAudioProcessingProperties().size();
-             ++j) {
+        for (wtf_size_t j = 0; j < GetAudioProcessingProperties().size(); ++j) {
           if (i == j)
             continue;
           EXPECT_FALSE(result.audio_processing_properties().*
@@ -1559,7 +1555,7 @@
             &MediaTrackConstraintSetPlatform::render_to_associated_sink,
         };
 
-    for (WTF::wtf_size_t i = 0; i < kConstraints.size(); ++i) {
+    for (wtf_size_t i = 0; i < kConstraints.size(); ++i) {
       SCOPED_TRACE(i);
       constraint_factory_.Reset();
       (constraint_factory_.basic().*kConstraints[i])
@@ -1619,7 +1615,7 @@
     ASSERT_EQ(kAudioProcessingConstraints.size(),
               GetAudioProcessingProperties().size());
 
-    for (WTF::wtf_size_t i = 0; i < kAudioProcessingConstraints.size(); ++i) {
+    for (wtf_size_t i = 0; i < kAudioProcessingConstraints.size(); ++i) {
       constraint_factory_.Reset();
       (constraint_factory_.basic().*kAudioProcessingConstraints[i])
           .SetExact(properties.*GetAudioProcessingProperties()[i]);
@@ -1686,7 +1682,7 @@
             &MediaTrackConstraintSetPlatform::disable_local_echo,
             &MediaTrackConstraintSetPlatform::render_to_associated_sink,
         };
-    for (WTF::wtf_size_t i = 0; i < kAudioBrowserConstraints.size(); ++i) {
+    for (wtf_size_t i = 0; i < kAudioBrowserConstraints.size(); ++i) {
       constraint_factory_.Reset();
       (constraint_factory_.basic().*kAudioBrowserConstraints[i])
           .SetExact(use_defaults);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.cc
index 4cfe574..4d74a4f0 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_sets.cc
@@ -401,7 +401,7 @@
   DCHECK_GE(vertices.size(), 1U);
   Point best_candidate(0, 0);
   double best_distance = HUGE_VAL;
-  for (WTF::wtf_size_t i = 0; i < vertices.size(); ++i) {
+  for (wtf_size_t i = 0; i < vertices.size(); ++i) {
     Point candidate = Point::ClosestPointInSegment(
         point, vertices[i], vertices[(i + 1) % vertices.size()]);
     double distance = Point::SquareEuclideanDistance(point, candidate);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
index d785cca..68219fbd 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
@@ -1038,8 +1038,7 @@
           : 0.0);
 
   // Favor IDs that appear first in the enumeration.
-  for (WTF::wtf_size_t i = 0; i < capabilities.device_capabilities.size();
-       ++i) {
+  for (wtf_size_t i = 0; i < capabilities.device_capabilities.size(); ++i) {
     if (device.device_id == capabilities.device_capabilities[i].device_id) {
       distance_vector->push_back(i);
       break;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer_test.cc
index 2f5436e..ba6fc79 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer_test.cc
@@ -48,7 +48,7 @@
       WebMediaStreamDeviceObserver::OnDeviceStoppedCb device_stopped_callback,
       WebMediaStreamDeviceObserver::OnDeviceRequestStateChangeCb
           request_state_change_callback) {
-    WTF::wtf_size_t previous_stream_size = observer_->label_stream_map_.size();
+    wtf_size_t previous_stream_size = observer_->label_stream_map_.size();
     blink::mojom::blink::StreamDevicesSet stream_devices_set;
     stream_devices_set.stream_devices.push_back(
         blink::mojom::blink::StreamDevices::New(
@@ -84,13 +84,12 @@
     EXPECT_EQ(streams.size(), expected_labels.size());
     for (size_t stream_index = 0; stream_index < streams.size();
          ++stream_index) {
-      EXPECT_EQ(streams[static_cast<WTF::wtf_size_t>(stream_index)]
-                    .video_devices.size(),
-                1u);
-      EXPECT_EQ(streams[static_cast<WTF::wtf_size_t>(stream_index)]
-                    .video_devices[0]
-                    .id,
-                expected_labels[stream_index]);
+      EXPECT_EQ(
+          streams[static_cast<wtf_size_t>(stream_index)].video_devices.size(),
+          1u);
+      EXPECT_EQ(
+          streams[static_cast<wtf_size_t>(stream_index)].video_devices[0].id,
+          expected_labels[stream_index]);
     }
   }
 
@@ -103,7 +102,7 @@
 
   const MediaStreamDeviceObserver::Stream& GetStream(
       const WTF::String& label,
-      WTF::wtf_size_t stream_index) const {
+      wtf_size_t stream_index) const {
     return GetStreams(label)[stream_index];
   }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_set.cc b/third_party/blink/renderer/modules/mediastream/media_stream_set.cc
index 03bc1d59f..94535d8 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_set.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_set.cc
@@ -79,8 +79,8 @@
   // The set will be initialized when all of its streams are initialized.
   // When the last stream is initialized, its callback will trigger
   // a call to OnMediaStreamSetInitialized.
-  for (WTF::wtf_size_t stream_index = 0;
-       stream_index < stream_descriptors.size(); ++stream_index) {
+  for (wtf_size_t stream_index = 0; stream_index < stream_descriptors.size();
+       ++stream_index) {
     MediaStream::Create(context, stream_descriptors[stream_index],
                         /*track=*/nullptr,
                         WTF::BindOnce(&MediaStreamSet::OnMediaStreamInitialized,
@@ -109,8 +109,8 @@
       MakeGarbageCollected<ScreenDetails>(window);
   const bool screen_details_match_descriptors =
       screen_details->screens().size() == stream_descriptors.size();
-  for (WTF::wtf_size_t stream_index = 0;
-       stream_index < stream_descriptors.size(); ++stream_index) {
+  for (wtf_size_t stream_index = 0; stream_index < stream_descriptors.size();
+       ++stream_index) {
     MediaStreamDescriptor* const descriptor = stream_descriptors[stream_index];
     DCHECK_EQ(1u, descriptor->NumberOfVideoComponents());
 
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
index e692fba..b23c5e8 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -2025,18 +2025,18 @@
                       V8MLOperandDataType::Enum::kInt8, exception_state);
 
     auto* input_scale =
-        BuildConstant(scope.GetScriptState(), builder, {},
+        BuildConstant(scope.GetScriptState(), builder, {1, 1, 1, 1},
                       V8MLOperandDataType::Enum::kFloat32, exception_state);
 
     auto* input_zero_point =
-        BuildConstant(scope.GetScriptState(), builder, {},
+        BuildConstant(scope.GetScriptState(), builder, {1, 1, 1, 1},
                       V8MLOperandDataType::Enum::kInt8, exception_state);
 
     auto* filter_scale =
-        BuildConstant(scope.GetScriptState(), builder, {},
+        BuildConstant(scope.GetScriptState(), builder, {1, 1, 1, 1},
                       V8MLOperandDataType::Enum::kFloat32, exception_state);
     auto* filter_zero_point =
-        BuildConstant(scope.GetScriptState(), builder, {},
+        BuildConstant(scope.GetScriptState(), builder, {1, 1, 1, 1},
                       V8MLOperandDataType::Enum::kInt8, exception_state);
 
     auto* dq0_output_operand =
@@ -2075,10 +2075,10 @@
         conv2d_output_operand, transpose_options2, exception_state);
     ASSERT_THAT(transpose2_output_operand, testing::NotNull());
     auto* output_scale =
-        BuildConstant(scope.GetScriptState(), builder, {},
+        BuildConstant(scope.GetScriptState(), builder, {1, 1, 1, 1},
                       V8MLOperandDataType::Enum::kFloat32, exception_state);
     auto* output_zero_point =
-        BuildConstant(scope.GetScriptState(), builder, {},
+        BuildConstant(scope.GetScriptState(), builder, {1, 1, 1, 1},
                       V8MLOperandDataType::Enum::kInt8, exception_state);
 
     auto* q_output_operand = builder->quantizeLinear(
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
index 6a26055..6957e26 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_proxy_test.cc
@@ -44,7 +44,7 @@
   if (received_data.size() != expected.size())
     return false;
 
-  for (WTF::wtf_size_t i = 0; i < received_data.size(); i++) {
+  for (wtf_size_t i = 0; i < received_data.size(); i++) {
     if (received_data[i] != expected[i]) {
       return false;
     }
diff --git a/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc b/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
index 008bf33..b7acf03 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
@@ -40,7 +40,7 @@
     return nullptr;
   NDEFMessagePtr message_ptr = NDEFMessage::New();
   message_ptr->data.resize(message->records().size());
-  for (wtf_size_t i = 0; i < message->records().size(); ++i) {
+  for (blink::wtf_size_t i = 0; i < message->records().size(); ++i) {
     NDEFRecordPtr record = NDEFRecord::From(message->records()[i].Get());
     DCHECK(record);
     message_ptr->data[i] = std::move(record);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
index 96a5869..28c5ab71 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
@@ -150,7 +150,7 @@
       }
     } else {
       // Replace certificates that have changed, if any
-      for (WTF::wtf_size_t i = 0; i < certs->GetSize(); i++) {
+      for (wtf_size_t i = 0; i < certs->GetSize(); i++) {
         auto& cert = certs->Get(i);
         webrtc::Buffer der_cert;
         cert.ToDER(&der_cert);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index e1c5b140e..63e304ad 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -1545,8 +1545,9 @@
   std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
       track_ref = track_adapter_map_->GetOrCreateLocalTrackAdapter(component);
   std::vector<std::string> stream_ids(descriptors.size());
-  for (WTF::wtf_size_t i = 0; i < descriptors.size(); ++i)
+  for (wtf_size_t i = 0; i < descriptors.size(); ++i) {
     stream_ids[i] = descriptors[i]->Id().Utf8();
+  }
 
   // Invoke native AddTrack() on the signaling thread and surface the resulting
   // transceiver.
@@ -1959,7 +1960,7 @@
     bool is_rollback) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   Vector<std::unique_ptr<RTCRtpTransceiverPlatform>> platform_transceivers(
-      base::checked_cast<WTF::wtf_size_t>(transceiver_states.size()));
+      base::checked_cast<wtf_size_t>(transceiver_states.size()));
   PeerConnectionTracker::TransceiverUpdatedReason update_reason =
       !is_remote_description ? PeerConnectionTracker::TransceiverUpdatedReason::
                                    kSetLocalDescription
@@ -1967,7 +1968,7 @@
                                    kSetRemoteDescription;
   Vector<uintptr_t> ids(
       base::checked_cast<wtf_size_t>(transceiver_states.size()));
-  for (WTF::wtf_size_t i = 0; i < transceiver_states.size(); ++i) {
+  for (wtf_size_t i = 0; i < transceiver_states.size(); ++i) {
     // Figure out if this transceiver is new or if setting the state modified
     // the transceiver such that it should be logged by the
     // |peer_connection_tracker_|.
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
index cf5e508..f3e698347 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver_impl.cc
@@ -191,8 +191,8 @@
     // secondary thread, which is the WebRTC worker thread.
     auto webrtc_sources = webrtc_receiver_->GetSources();
     Vector<std::unique_ptr<RTCRtpSource>> sources(
-        static_cast<WTF::wtf_size_t>(webrtc_sources.size()));
-    for (WTF::wtf_size_t i = 0; i < webrtc_sources.size(); ++i) {
+        static_cast<wtf_size_t>(webrtc_sources.size()));
+    for (wtf_size_t i = 0; i < webrtc_sources.size(); ++i) {
       sources[i] = std::make_unique<RTCRtpSource>(webrtc_sources[i]);
     }
     return sources;
@@ -329,10 +329,10 @@
 
 Vector<String> RTCRtpReceiverImpl::StreamIds() const {
   const auto& stream_ids = internal_->state().stream_ids();
-  Vector<String> wtf_stream_ids(
-      static_cast<WTF::wtf_size_t>(stream_ids.size()));
-  for (WTF::wtf_size_t i = 0; i < stream_ids.size(); ++i)
+  Vector<String> wtf_stream_ids(static_cast<wtf_size_t>(stream_ids.size()));
+  for (wtf_size_t i = 0; i < stream_ids.size(); ++i) {
     wtf_stream_ids[i] = String::FromUTF8(stream_ids[i]);
+  }
   return wtf_stream_ids;
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
index b3d3c84..31bfc81 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc
@@ -492,7 +492,7 @@
   webrtc::RtpCodec webrtc_codec;
   std::string mime_type = codec->mimeType().Utf8();
   auto slash_index = codec->mimeType().Find("/");
-  if (slash_index == WTF::kNotFound) {
+  if (slash_index == kNotFound) {
     webrtc_codec.kind = webrtc::MediaType::UNSUPPORTED;
     return webrtc_codec;
   }
@@ -519,7 +519,7 @@
       WTF::String parameter = fmtp_split.StripWhiteSpace();
       auto equal_index = parameter.Find("=");
       std::string name, value;
-      if (equal_index == WTF::kNotFound) {
+      if (equal_index == kNotFound) {
         // Handle parameters without any equal signs, such as RED "111/111"
         name = "";
         value = parameter.Utf8();
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
index 801aebf..8880892 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.cc
@@ -270,7 +270,7 @@
 
     new_parameters.degradation_preference = degradation_preference;
 
-    for (WTF::wtf_size_t i = 0; i < new_parameters.encodings.size(); ++i) {
+    for (wtf_size_t i = 0; i < new_parameters.encodings.size(); ++i) {
       // Encodings have other parameters in the native layer that aren't exposed
       // to the blink layer. So instead of copying the new struct over the old
       // one, we copy the members one by one over the old struct, effectively
@@ -500,10 +500,10 @@
 
 Vector<String> RTCRtpSenderImpl::StreamIds() const {
   const auto& stream_ids = internal_->state().stream_ids();
-  Vector<String> wtf_stream_ids(
-      static_cast<WTF::wtf_size_t>(stream_ids.size()));
-  for (WTF::wtf_size_t i = 0; i < stream_ids.size(); ++i)
+  Vector<String> wtf_stream_ids(static_cast<wtf_size_t>(stream_ids.size()));
+  for (wtf_size_t i = 0; i < stream_ids.size(); ++i) {
     wtf_stream_ids[i] = String::FromUTF8(stream_ids[i]);
+  }
   return wtf_stream_ids;
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
index f40d0236..81d9c976 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
@@ -259,7 +259,7 @@
     codec_preferences.emplace_back();
     auto& webrtc_codec = codec_preferences.back();
     auto slash_position = codec->mimeType().find('/');
-    if (slash_position == WTF::kNotFound) {
+    if (slash_position == kNotFound) {
       exception_state.ThrowDOMException(
           DOMExceptionCode::kInvalidModificationError, "Invalid codec");
       return;
@@ -281,7 +281,7 @@
     }
     if (codec->hasSdpFmtpLine()) {
       auto sdpFmtpLine = codec->sdpFmtpLine();
-      if (sdpFmtpLine.find('=') == WTF::kNotFound) {
+      if (sdpFmtpLine.find('=') == kNotFound) {
         // Some parameters don't follow the key=value form.
         webrtc_codec.parameters.emplace("", sdpFmtpLine.Ascii());
       } else {
@@ -289,7 +289,7 @@
         sdpFmtpLine.Split(';', parameters);
         for (const auto& parameter : parameters) {
           auto equal_position = parameter.find('=');
-          if (equal_position == WTF::kNotFound) {
+          if (equal_position == kNotFound) {
             exception_state.ThrowDOMException(
                 DOMExceptionCode::kInvalidModificationError, "Invalid codec");
             return;
diff --git a/third_party/blink/renderer/modules/screen_details/screen_details.cc b/third_party/blink/renderer/modules/screen_details/screen_details.cc
index ac82ea94..b915434 100644
--- a/third_party/blink/renderer/modules/screen_details/screen_details.cc
+++ b/third_party/blink/renderer/modules/screen_details/screen_details.cc
@@ -76,7 +76,7 @@
   // instead of keeping some more efficient cache of display ids.
 
   // Check if any screens have been removed and remove them from `screens_`.
-  for (WTF::wtf_size_t i = 0; i < screens_.size();
+  for (wtf_size_t i = 0; i < screens_.size();
        /*conditionally incremented*/) {
     if (base::Contains(new_infos.screen_infos, screens_[i]->DisplayId(),
                        &display::ScreenInfo::display_id)) {
diff --git a/third_party/blink/renderer/modules/vibration/vibration_controller.cc b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
index 1dc06cf..6825d95 100644
--- a/third_party/blink/renderer/modules/vibration/vibration_controller.cc
+++ b/third_party/blink/renderer/modules/vibration/vibration_controller.cc
@@ -38,7 +38,7 @@
 blink::VibrationController::VibrationPattern sanitizeVibrationPatternInternal(
     const blink::VibrationController::VibrationPattern& pattern) {
   blink::VibrationController::VibrationPattern sanitized = pattern;
-  wtf_size_t length = sanitized.size();
+  blink::wtf_size_t length = sanitized.size();
 
   // If the pattern is too long then truncate it.
   if (length > kVibrationPatternLengthMax) {
@@ -47,7 +47,7 @@
   }
 
   // If any pattern entry is too long then truncate it.
-  for (wtf_size_t i = 0; i < length; ++i) {
+  for (blink::wtf_size_t i = 0; i < length; ++i) {
     if (sanitized[i] > kVibrationDurationMsMax)
       sanitized[i] = kVibrationDurationMsMax;
   }
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 84e5b1e..9284b32 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -9,6 +9,7 @@
 #include "base/strings/to_string.h"
 #include "build/build_config.h"
 #include "media/audio/audio_device_description.h"
+#include "base/trace_event/trace_event.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -249,9 +250,15 @@
   audio_context->MaybeAllowAutoplayWithUnlockType(
       AutoplayUnlockType::kContextConstructor);
   if (audio_context->IsAllowedToStart(/*should_suppress_warning=*/true)) {
+    TRACE_EVENT1("webaudio", "AudioContext::Create - allowed to start",
+                 "UUID", audio_context->Uuid());
     audio_context->StartRendering();
     audio_context->SetContextState(V8AudioContextState::Enum::kRunning);
+  } else {
+    TRACE_EVENT1("webaudio", "AudioContext::Create - NOT allowed to start",
+                 "UUID", audio_context->Uuid());
   }
+
 #if DEBUG_AUDIONODE_REFERENCES
   fprintf(stderr, "[%16p]: AudioContext::AudioContext(): %u #%u\n",
           audio_context, audio_context->context_id_, hardware_context_count);
@@ -306,6 +313,9 @@
       this, sink_descriptor_, latency_hint, sample_rate,
       update_echo_cancellation_on_first_start);
 
+  TRACE_EVENT2("webaudio", "AudioContext::AudioContext", "UUID", Uuid(),
+               "AutoplayPolicy", static_cast<int>(GetAutoplayPolicy()));
+
   switch (GetAutoplayPolicy()) {
     case AutoplayPolicy::Type::kNoUserGestureRequired:
       CHECK(window.document());
@@ -640,6 +650,7 @@
 void AudioContext::StartRendering() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
   SendLogMessage(__func__, "");
+  TRACE_EVENT1("webaudio", __func__, "UUID", Uuid());
 
   if (!keep_alive_) {
     keep_alive_ = this;
@@ -650,6 +661,7 @@
 void AudioContext::StopRendering() {
   DCHECK(destination());
   SendLogMessage(__func__, "");
+  TRACE_EVENT1("webaudio", __func__, "UUID", Uuid());
 
   // It is okay to perform the following on a suspended AudioContext because
   // this method gets called from ExecutionContext::ContextDestroyed() meaning
@@ -665,6 +677,8 @@
 void AudioContext::SuspendRendering() {
   DCHECK(destination());
   SendLogMessage(__func__, "");
+  TRACE_EVENT2("webaudio", __func__, "UUID", Uuid(),
+               "state", static_cast<int>(ContextState()));
 
   if (ContextState() == V8AudioContextState::Enum::kRunning ||
       ContextState() == V8AudioContextState::Enum::kInterrupted) {
@@ -1323,6 +1337,8 @@
 void AudioContext::FrameVisibilityChanged(
     mojom::blink::FrameVisibility frame_visibility) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
+  TRACE_EVENT2("webaudio", __func__, "UUID", Uuid(),
+               "frame_visibility", static_cast<int>(frame_visibility));
 
   bool is_frame_hidden =
       (frame_visibility == mojom::blink::FrameVisibility::kNotRendered);
@@ -1390,6 +1406,8 @@
 
 void AudioContext::ResumeOnPrerenderActivation() {
   CHECK(blocked_by_prerendering_);
+  TRACE_EVENT2("webaudio", __func__, "UUID", Uuid(),
+               "state", static_cast<int>(ContextState()));
   blocked_by_prerendering_ = false;
   switch (ContextState()) {
     case V8AudioContextState::Enum::kSuspended:
@@ -1421,6 +1439,8 @@
 
 void AudioContext::StartContextInterruption() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
+  TRACE_EVENT2("webaudio", __func__, "UUID", Uuid(),
+               "state", static_cast<int>(ContextState()));
   if (!RuntimeEnabledFeatures::AudioContextInterruptedStateEnabled()) {
     return;
   }
@@ -1447,6 +1467,8 @@
 
 void AudioContext::EndContextInterruption() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
+  TRACE_EVENT2("webaudio", __func__, "UUID", Uuid(),
+               "state", static_cast<int>(ContextState()));
   if (!RuntimeEnabledFeatures::AudioContextInterruptedStateEnabled()) {
     return;
   }
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
index 36da21a..210d562 100644
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
@@ -313,6 +313,8 @@
 
   // Post a cross-thread task only when the detecting condition has changed.
   if (is_detecting_silence_ != needs_silence_detection) {
+    TRACE_EVENT1("webaudio", __func__,
+                 "needs_silence_detection (changed)", needs_silence_detection);
     PostCrossThreadTask(
         *task_runner_, FROM_HERE,
         CrossThreadBindOnce(&RealtimeAudioDestinationHandler::SetDetectSilence,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 7ef9730..3860e2df 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -9248,7 +9248,7 @@
     // exists in the list, too. Clear it out from there so that its
     // new addition doesn't introduce a duplicate.
     wtf_size_t old_index = program_completion_query_list_.Find(program);
-    DCHECK_NE(old_index, WTF::kNotFound);
+    DCHECK_NE(old_index, kNotFound);
     program_completion_query_list_.EraseAt(old_index);
   }
   program_completion_query_map_.Set(program, query);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
index 0685d42..dbeb563 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
@@ -48,7 +48,7 @@
   }
 
   wgpu::ShaderModule shader_module;
-  bool has_null_character = (wtf_wgsl_code.find('\0') != WTF::kNotFound);
+  bool has_null_character = (wtf_wgsl_code.find('\0') != kNotFound);
   if (has_null_character) {
     shader_module = device->GetHandle().CreateErrorShaderModule(
         &dawn_desc, "The WGSL shader contains an illegal character '\\0'");
diff --git a/third_party/blink/renderer/modules/websockets/websocket_common_test.cc b/third_party/blink/renderer/modules/websockets/websocket_common_test.cc
index ba3321d..270b17b 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_common_test.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_common_test.cc
@@ -37,7 +37,7 @@
   }
   for (size_t i = 0; i < 256; ++i) {
     LChar to_check = static_cast<LChar>(i);
-    if (valid_characters.find(to_check) != WTF::kNotFound) {
+    if (valid_characters.find(to_check) != kNotFound) {
       continue;
     }
     String s(base::span_from_ref(to_check));
diff --git a/third_party/blink/renderer/modules/xr/xr_cube_map.cc b/third_party/blink/renderer/modules/xr/xr_cube_map.cc
index a1f74ce..ba9e4991 100644
--- a/third_party/blink/renderer/modules/xr/xr_cube_map.cc
+++ b/third_party/blink/renderer/modules/xr/xr_cube_map.cc
@@ -122,8 +122,8 @@
     // Since ARCore provides texture as half float components, we need to do a
     // conversion first to support this path.
     // TODO(https://crbug.com/1148605): Do conversions off the main JS thread.
-    WTF::wtf_size_t component_count = width_and_height_ * width_and_height_ * 4;
-    WTF::Vector<uint8_t> sRGB(component_count);
+    wtf_size_t component_count = width_and_height_ * width_and_height_ * 4;
+    Vector<uint8_t> sRGB(component_count);
     for (int i = 0; i < 6; ++i) {
       Rgba16fToSrgba8(cubemap_images[i], sRGB);
       auto target = cubemap_targets[i];
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index d224ecc..7e1f310c 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -1985,7 +1985,7 @@
     DVLOG(3) << ": got image_trackable_scores";
     DCHECK(!tracked_image_scores_available_);
     auto& scores = images_data->image_trackable_scores.value();
-    for (WTF::wtf_size_t index = 0; index < scores.size(); ++index) {
+    for (wtf_size_t index = 0; index < scores.size(); ++index) {
       tracked_image_scores_.push_back(V8XRImageTrackingScore(
           scores[index] ? V8XRImageTrackingScore::Enum::kTrackable
                         : V8XRImageTrackingScore::Enum::kUntrackable));
diff --git a/third_party/blink/renderer/platform/exported/web_string.cc b/third_party/blink/renderer/platform/exported/web_string.cc
index a161951c..ea62e8f 100644
--- a/third_party/blink/renderer/platform/exported/web_string.cc
+++ b/third_party/blink/renderer/platform/exported/web_string.cc
@@ -142,7 +142,7 @@
     return std::string::npos;
   }
   wtf_size_t pos = impl_->Find(s.impl_.get());
-  return pos != WTF::kNotFound ? pos : std::string::npos;
+  return pos != kNotFound ? pos : std::string::npos;
 }
 
 size_t WebString::Find(std::string_view characters) const {
@@ -150,7 +150,7 @@
     return std::string::npos;
   }
   wtf_size_t pos = impl_->Find(characters.data());
-  return pos != WTF::kNotFound ? pos : std::string::npos;
+  return pos != kNotFound ? pos : std::string::npos;
 }
 
 bool WebString::operator<(const WebString& other) const {
diff --git a/third_party/blink/renderer/platform/fonts/font_cache_test.cc b/third_party/blink/renderer/platform/fonts/font_cache_test.cc
index 1ad8e4a..bf903fb 100644
--- a/third_party/blink/renderer/platform/fonts/font_cache_test.cc
+++ b/third_party/blink/renderer/platform/fonts/font_cache_test.cc
@@ -23,7 +23,7 @@
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 StringView MaybeStripFontationsSuffix(const String& font_name) {
   wtf_size_t found_index = font_name.ReverseFind(" (Fontations)");
-  if (found_index != WTF::kNotFound) {
+  if (found_index != kNotFound) {
     return StringView(font_name, 0, found_index);
   } else {
     return font_name;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/frame_shape_cache.cc b/third_party/blink/renderer/platform/fonts/shaping/frame_shape_cache.cc
index ed05642..1827c5d 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/frame_shape_cache.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/frame_shape_cache.cc
@@ -135,7 +135,7 @@
   NodeEntry* entry =
       FindOrCreateEntry(text, direction, node_map_, node_lru_list_);
   const PlainTextNode* node = entry->node;
-  if (node && entry->list_index != WTF::kNotFound) {
+  if (node && entry->list_index != kNotFound) {
     // Touch ShapeResult cache entries for words in the hit node.
     for (const auto& item : node->ItemList()) {
       ShapeEntry* shape_entry =
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index 69aaa157..13d5eef1 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -1106,8 +1106,8 @@
                                    TextDirection direction,
                                    unsigned start,
                                    unsigned end) const {
-  DCHECK_GE(end, start);
-  DCHECK_LE(end, text_.length());
+  CHECK_GE(end, start);
+  CHECK_LE(end, text_.length());
 
   const unsigned length = end - start;
   ShapeResult* result =
@@ -1156,8 +1156,8 @@
     unsigned end,
     const Vector<RunSegmenter::RunSegmenterRange>& ranges,
     ShapeOptions options) const {
-  DCHECK_GE(end, start);
-  DCHECK_LE(end, text_.length());
+  CHECK_GE(end, start);
+  CHECK_LE(end, text_.length());
   DCHECK_GT(ranges.size(), 0u);
   DCHECK_EQ(start, ranges[0].start);
   DCHECK_EQ(end, ranges[ranges.size() - 1].end);
@@ -1186,8 +1186,8 @@
     unsigned end,
     const RunSegmenter::RunSegmenterRange pre_segmented,
     ShapeOptions options) const {
-  DCHECK_GE(end, start);
-  DCHECK_LE(end, text_.length());
+  CHECK_GE(end, start);
+  CHECK_LE(end, text_.length());
   DCHECK_GE(start, pre_segmented.start);
   DCHECK_LE(end, pre_segmented.end);
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
index 3c31e19..e53515c5 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -183,7 +183,7 @@
 
   StringView MaybeStripFontationsSuffix(const String& font_name) {
     wtf_size_t found_index = font_name.ReverseFind(" (Fontations)");
-    if (found_index != WTF::kNotFound) {
+    if (found_index != kNotFound) {
       return StringView(font_name, 0, found_index);
     } else {
       return font_name;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index ad32764..e77047f3 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -2276,11 +2276,9 @@
              : 0;
 }
 
-namespace {
-
-void AddRunInfoRanges(const ShapeResultRun& run_info,
-                      float offset,
-                      Vector<CharacterRange>* ranges) {
+void ShapeResult::AddRunInfoRanges(const ShapeResultRun& run_info,
+                                   float offset,
+                                   Vector<CharacterRange>* ranges) {
   Vector<float> character_widths(run_info.num_characters_);
   for (const auto& glyph : run_info.glyph_data_) {
     // TODO(crbug.com/1147011): This should not happen, but crash logs indicate
@@ -2308,8 +2306,6 @@
   }
 }
 
-}  // anonymous namespace
-
 float ShapeResult::IndividualCharacterRanges(Vector<CharacterRange>* ranges,
                                              float start_x) const {
   DCHECK(ranges);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index c4b5597..8655c87f 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -517,6 +517,10 @@
   friend class ShapeResultTest;
   friend class StretchyOperatorShaper;
 
+  static void AddRunInfoRanges(const ShapeResultRun& run_info,
+                               float offset,
+                               Vector<CharacterRange>* ranges);
+
   template <bool has_non_zero_glyph_offsets>
   float ForEachGlyphImpl(float initial_advance,
                          GlyphCallback,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
index 1171ef7e..0b9d5a9 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
@@ -420,6 +420,24 @@
 #endif
   }
 
+ private:
+  friend class GlyphDataRange;
+  friend class HarfBuzzShaper;
+  friend class ShapeResult;
+  friend class ShapeResultBuffer;
+  friend class ShapeResultTest;
+  friend class ShapeResultTestInfo;
+  friend class ShapeResultView;
+  friend class ShapeResultRunTest;
+  FRIEND_TEST_ALL_PREFIXES(GlyphDataRangeTest, Data);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataCopyConstructor);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataCopyFromRange);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataReverse);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataAddOffsetHeightAt);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataAddOffsetWidthAt);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataSetAt);
+  FRIEND_TEST_ALL_PREFIXES(ShapeResultRunTest, GlyphDataShrink);
+
   GlyphDataCollection glyph_data_;
   Member<SimpleFontData> font_data_;
 
diff --git a/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc b/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
index 83c5eea..eba653d 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
+++ b/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
@@ -39,8 +39,9 @@
 void CompositorFilterOperations::AppendColorMatrixFilter(Vector<float> values) {
   DCHECK_EQ(values.size(), 20u);
   cc::FilterOperation::Matrix matrix = {};
-  for (WTF::wtf_size_t i = 0; i < values.size(); ++i)
+  for (wtf_size_t i = 0; i < values.size(); ++i) {
     matrix[i] = values[i];
+  }
   filter_operations_.Append(
       cc::FilterOperation::CreateColorMatrixFilter(matrix));
 }
diff --git a/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md b/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
index ae2ef2e..f614575 100644
--- a/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
+++ b/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
@@ -478,14 +478,14 @@
 
 Collections compared to other libraries used in Blink:
 
-| stdlib             | WTF                 | Oilpan                    |
-| ------------------ | ------------------- | ------------------------- |
-| std::vector        | WTF::Vector         | blink::HeapVector         |
-| std::deque         | WTF::Deque          | blink::HeapDeque          |
-| std::unordered_map | WTF::HashMap        | blink::HeapHashMap        |
-| std::unordered_set | WTF::HashSet        | blink::HeapHashSet        |
-| -                  | WTF::LinkedHashSet  | blink::HeapLinkedHashSet  |
-| -                  | WTF::HashCountedSet | blink::HeapHashCountedSet |
+| stdlib             | WTF                   | Oilpan                    |
+| ------------------ | --------------------- | ------------------------- |
+| std::vector        | blink::Vector         | blink::HeapVector         |
+| std::deque         | blink::Deque          | blink::HeapDeque          |
+| std::unordered_map | blink::HashMap        | blink::HeapHashMap        |
+| std::unordered_set | blink::HashSet        | blink::HeapHashSet        |
+| -                  | blink::LinkedHashSet  | blink::HeapLinkedHashSet  |
+| -                  | blink::HashCountedSet | blink::HeapHashCountedSet |
 
 These heap collections work mostly the same way as their stdlib or WTF collection counterparts but there are some things to keep in mind.
 Heap collections are regular heap objects and thus must be properly traced from a `Trace` method.
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
index cb74dfc..1875b58 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -425,7 +425,7 @@
   // Clears decoded pixel data from all frames except the provided frame. If
   // subsequent frames depend on this frame's required previous frame, then that
   // frame is also kept in cache to prevent re-decoding from the beginning.
-  // Callers may pass WTF::kNotFound to clear all frames.
+  // Callers may pass kNotFound to clear all frames.
   // Note: If |frame_buffer_cache_| contains only one frame, it won't be
   // cleared. Returns the number of bytes of frame data actually cleared.
   virtual wtf_size_t ClearCacheExceptFrame(wtf_size_t);
@@ -461,7 +461,7 @@
   // order to decode frame |frame_index|, based on frame disposal methods
   // and |frame_rect_is_opaque|, where |frame_rect_is_opaque| signifies whether
   // the rectangle of frame at |frame_index| is known to be opaque.
-  // If no previous frame's data is required, returns WTF::kNotFound.
+  // If no previous frame's data is required, returns kNotFound.
   //
   // This function requires that the previous frame's
   // |required_previous_frame_index_| member has been set correctly. The
diff --git a/third_party/blink/renderer/platform/image-decoders/image_frame.h b/third_party/blink/renderer/platform/image-decoders/image_frame.h
index 113982d..92351c43 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_frame.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_frame.h
@@ -340,7 +340,7 @@
   bool pixels_changed_ = false;
 
   // The frame that must be decoded before this frame can be decoded.
-  // WTF::kNotFound if this frame doesn't require any previous frame.
+  // kNotFound if this frame doesn't require any previous frame.
   // This is used by ImageDecoder::ClearCacheExceptFrame(), and will never
   // be read for image formats that do not have multiple frames.
   wtf_size_t required_previous_frame_index_ = kNotFound;
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 d1760e06..762c3b4 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -600,11 +600,7 @@
                  mojom::blink::RequestContextType::PING ||
              resource_request.GetRequestContext() ==
                  mojom::blink::RequestContextType::CSP_REPORT) {
-    if (base::FeatureList::IsEnabled(features::kSetLowPriorityForBeacon)) {
-      priority = ResourceLoadPriority::kLow;
-    } else {
-      priority = ResourceLoadPriority::kVeryLow;
-    }
+    priority = ResourceLoadPriority::kVeryLow;
   }
 
   priority = AdjustPriorityWithPriorityHintAndRenderBlocking(
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 2a65905..7531c80 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -136,39 +136,6 @@
          context != mojom::blink::RequestContextType::AUDIO;
 }
 
-void LogMixedAutoupgradeMetrics(blink::MixedContentAutoupgradeStatus status,
-                                std::optional<int> response_or_error_code,
-                                ukm::SourceId source_id,
-                                ukm::UkmRecorder* recorder,
-                                Resource* resource) {
-  UMA_HISTOGRAM_ENUMERATION("MixedAutoupgrade.ResourceRequest.Status", status);
-  switch (status) {
-    case MixedContentAutoupgradeStatus::kStarted:
-      UMA_HISTOGRAM_ENUMERATION("MixedAutoupgrade.ResourceRequest.Start.Type",
-                                resource->GetType());
-      break;
-    case MixedContentAutoupgradeStatus::kFailed:
-      UMA_HISTOGRAM_ENUMERATION("MixedAutoupgrade.ResourceRequest.Failure.Type",
-                                resource->GetType());
-      UMA_HISTOGRAM_BOOLEAN("MixedAutoupgrade.ResourceRequest.Failure.IsAd",
-                            resource->GetResourceRequest().IsAdResource());
-      break;
-    case MixedContentAutoupgradeStatus::kResponseReceived:
-      UMA_HISTOGRAM_ENUMERATION(
-          "MixedAutoupgrade.ResourceRequest.Response.Type",
-          resource->GetType());
-  };
-  ukm::builders::MixedContentAutoupgrade_ResourceRequest builder(source_id);
-  builder.SetStatus(static_cast<int64_t>(status));
-  if (response_or_error_code.has_value()) {
-    base::UmaHistogramSparse(
-        "MixedAutoupgrade.ResourceRequest.ErrorOrResponseCode",
-        response_or_error_code.value());
-    builder.SetCode(response_or_error_code.value());
-  }
-  builder.Record(recorder);
-}
-
 bool RequestContextObserveResponse(mojom::blink::RequestContextType type) {
   switch (type) {
     case mojom::blink::RequestContextType::PING:
@@ -365,11 +332,6 @@
     throttle_option = ResourceLoadScheduler::ThrottleOption::kStoppable;
   }
 
-  if (request.IsAutomaticUpgrade()) {
-    LogMixedAutoupgradeMetrics(MixedContentAutoupgradeStatus::kStarted,
-                               std::nullopt, request.GetUkmSourceId(),
-                               fetcher_->UkmRecorder(), resource_);
-  }
   if (resource_->GetResourceRequest().IsDownloadToNetworkCacheOnly()) {
     // The download-to-cache requests are throttled in net/, they are fire-and
     // forget, and cannot unregister properly from the scheduler once they are
@@ -915,13 +877,6 @@
   CountPrivateNetworkAccessPreflightResult(
       response.PrivateNetworkAccessPreflightResult());
 
-  if (request.IsAutomaticUpgrade()) {
-    LogMixedAutoupgradeMetrics(MixedContentAutoupgradeStatus::kResponseReceived,
-                               response.HttpStatusCode(),
-                               request.GetUkmSourceId(),
-                               fetcher_->UkmRecorder(), resource_);
-  }
-
   ResourceType resource_type = resource_->GetType();
 
   const ResourceRequestHead& initial_request = resource_->GetResourceRequest();
@@ -1193,15 +1148,8 @@
                              int64_t encoded_data_length,
                              uint64_t encoded_body_length,
                              int64_t decoded_body_length) {
-  const ResourceRequestHead& request = resource_->GetResourceRequest();
   response_end_time_for_error_cases_ = response_end_time;
 
-  if (request.IsAutomaticUpgrade()) {
-    LogMixedAutoupgradeMetrics(MixedContentAutoupgradeStatus::kFailed,
-                               error.reason(), request.GetUkmSourceId(),
-                               fetcher_->UkmRecorder(), resource_);
-  }
-
   CountPrivateNetworkAccessPreflightResult(
       error.private_network_access_preflight_result());
 
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index c603b46cb..3ba207b 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -45,7 +45,6 @@
 #include "media/base/limits.h"
 #include "media/base/media_content_type.h"
 #include "media/base/media_log.h"
-#include "media/base/media_player_logging_id.h"
 #include "media/base/media_switches.h"
 #include "media/base/memory_dump_provider_proxy.h"
 #include "media/base/output_device_info.h"
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.h b/third_party/blink/renderer/platform/media/web_media_player_impl.h
index d953cd8..a79548f 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.h
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.h
@@ -32,6 +32,7 @@
 #include "media/base/eme_constants.h"
 #include "media/base/encryption_scheme.h"
 #include "media/base/media_observer.h"
+#include "media/base/media_player_logging_id.h"
 #include "media/base/media_tracks.h"
 #include "media/base/overlay_info.h"
 #include "media/base/picture_in_picture_events_info.h"
@@ -568,11 +569,11 @@
   void ReportMemoryUsage();
   void FinishMemoryUsageReport(int64_t demuxer_memory_usage);
 
-  void OnMainThreadMemoryDump(int32_t id,
+  void OnMainThreadMemoryDump(media::MediaPlayerLoggingID id,
                               const base::trace_event::MemoryDumpArgs& args,
                               base::trace_event::ProcessMemoryDump* pmd);
   static void OnMediaThreadMemoryDump(
-      int32_t id,
+      media::MediaPlayerLoggingID id,
       media::Demuxer* demuxer,
       const base::trace_event::MemoryDumpArgs& args,
       base::trace_event::ProcessMemoryDump* pmd);
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index 5d22564e..6e735d9 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -139,7 +139,7 @@
     typename OutElement = decltype(ConvertToBlink(std::declval<InElement>()))>
 ::blink::Vector<OutElement> ConvertToBlink(const std::vector<InElement>& in) {
   ::blink::Vector<OutElement> out;
-  out.reserve(base::checked_cast<wtf_size_t>(in.size()));
+  out.reserve(base::checked_cast<::blink::wtf_size_t>(in.size()));
   for (const auto& element : in) {
     out.push_back(ConvertToBlink(element));
   }
diff --git a/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc b/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc
index 5bbbe97..f95b4b0 100644
--- a/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers_fuzzer.cc
@@ -28,7 +28,7 @@
   base::TimeDelta delay;
   blink::String url;
   blink::ResourceResponse response;
-  wtf_size_t end;
+  blink::wtf_size_t end;
 
   // SAFETY: libfuzzer provides a valid pointer and size pair.
   auto data_span = UNSAFE_BUFFERS(base::span(data, size));
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
index cfc6e7e..cd60778 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_video_encoder.cc
@@ -718,8 +718,7 @@
 scoped_refptr<gpu::ClientSharedImage> CreateClientSharedImage(
     media::GpuVideoAcceleratorFactories* gpu_factories,
     gfx::Size size) {
-  const auto buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
-  const auto si_format = viz::GetSharedImageFormat(buffer_format);
+  const auto si_format = viz::MultiPlaneFormat::kNV12;
   const auto buffer_usage =
       gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE;
 
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
index e558720..e4a33c5 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.cc
@@ -499,7 +499,8 @@
         update_rect->height()});
   }
 
-  if (ShouldSetColorSpace(frame->ColorSpace())) {
+  if (frame->ColorSpace().IsValid() &&
+      base::FeatureList::IsEnabled(media::kWebRTCColorAccuracy)) {
     frame_builder.set_color_space(GfxToWebRtcColorSpace(frame->ColorSpace()));
   }
   OnFrame(frame_builder.build());
@@ -508,17 +509,6 @@
   accumulated_update_rect_ = gfx::Rect();
 }
 
-bool WebRtcVideoTrackSource::ShouldSetColorSpace(
-    const gfx::ColorSpace& color_space) {
-  if (!base::FeatureList::IsEnabled(media::kWebRTCColorAccuracy)) {
-    return false;
-  }
-
-  // The remote end will assume REC601 if not instructed otherwise, so there's
-  // no need to pass this information on the wire.
-  return color_space.IsValid() &&
-         color_space != gfx::ColorSpace::CreateREC601();
-}
 
 void WebRtcVideoTrackSource::Dispose() {
   callback_proxy_->Reset();
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
index b8dc1d18..84ec15e 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source.h
@@ -127,10 +127,6 @@
 
   void TryProcessPendingFrames();
 
-  // This checks if the colorspace information should be passed to webrtc. Avoid
-  // sending unknown or unnecessary color space.
-  bool ShouldSetColorSpace(const gfx::ColorSpace& color_space);
-
   // |thread_checker_| is bound to the libjingle worker thread.
   THREAD_CHECKER(thread_checker_);
   scoped_refptr<WebRtcVideoFrameAdapter::SharedResources> adapter_resources_;
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
index c97cf6e..1b4b5759 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_video_track_source_test.cc
@@ -340,14 +340,18 @@
         EXPECT_EQ(frame.color_space().value().range(),
                   webrtc::ColorSpace::RangeID::kFull);
       }));
-
-  // For default REC709{BT709,BT709,BT709,Limited}, we will not set color space
-  // and transmit it by RTP since decoder side would guess it if color space is
-  // invalid.
   EXPECT_CALL(mock_sink_, OnFrame(_))
       .InSequence(s)
       .WillOnce(Invoke([](const webrtc::VideoFrame& frame) {
-        EXPECT_FALSE(frame.color_space().has_value());
+        ASSERT_TRUE(frame.color_space().has_value());
+        EXPECT_EQ(frame.color_space().value().matrix(),
+                  webrtc::ColorSpace::MatrixID::kSMPTE170M);
+        EXPECT_EQ(frame.color_space().value().transfer(),
+                  webrtc::ColorSpace::TransferID::kSMPTE170M);
+        EXPECT_EQ(frame.color_space().value().primaries(),
+                  webrtc::ColorSpace::PrimaryID::kSMPTE170M);
+        EXPECT_EQ(frame.color_space().value().range(),
+                  webrtc::ColorSpace::RangeID::kLimited);
       }));
 
   gfx::ColorSpace color_range_limited(
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index a6d35fa..e5a53a4 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4600,6 +4600,14 @@
       name: "SpecCompliantJsonMimeTypes",
       status: "stable",
     },
+    // This is a flag that re-enables some deprecated/removed "special rules"
+    // that apply to the styles of an <h1> element nested within <article>,
+    // <aside>, <nav>, or <section>. It is disabled by default, and here as a
+    // Finch killswitch only. This was shipped (disabled) in M140, and the flag
+    // can be removed in M142.
+    {
+      name: "SpecialRulesForNestedH1Elements",
+    },
     {
       name: "SpeculationRulesPrefetchWithSubresources",
     },
@@ -5151,6 +5159,7 @@
       // This flag uses the original DOM text for input when the password
       // echo is enabled to create the offset_map.
       name: "UseOriginalDomOffsetsForOffsetMap",
+      status: "test",
     },
     {
       name: "UsePositionForPointInFlexibleBoxWithSingleChildElement",
@@ -5478,7 +5487,6 @@
     },
     {
       name: "WebFontResizeLCP",
-      status: "experimental",
     },
     {
       name: "WebGLDeveloperExtensions",
diff --git a/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md b/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
index 1a2e08d..de3a56d 100644
--- a/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
+++ b/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
@@ -24,8 +24,8 @@
 posted via `TaskRunner::PostTask` or `TaskRunner::PostDelayedTask` interface.
 The regular method of creating closures, `base::BindOnce/Repeating`,
 [is banned](#binding-tasks). Blink should use one of the followings:
-- `WTF::Bind`: for tasks which are posted to the same thread.
-- `CrossThreadBind`:
+- `blink::BindOnce/Repeating`: for tasks which are posted to the same thread.
+- `blink::CrossThreadBindOnce/Repeating`:
     [for tasks which are posted to a different thread](#off-main-thread-scheduling).
 
 At the moment Blink Scheduler treats tasks as an atomic unit — if a task has
@@ -180,12 +180,12 @@
 
 Many data structures in Blink are bound to a particular thread (e.g. Strings,
 garbage-collected classes, etc), so it’s not safe to pass a pointer to them to
-another thread. To enforce this, `base::Bind` is banned in Blink and `WTF::Bind`
-and `CrossThreadBind` are provided as alternatives. `WTF::Bind` should be used
-to post tasks to the same thread and closures returned by it DCHECK that
-they run on the same thread. `CrossThreadBind` applies `CrossThreadCopier`
-to its arguments and creates a deep copy, so the resulting closure can run
-on a different thread.
+another thread. To enforce this, `base::Bind*` is banned in Blink and
+`blink::Bind*` and `blink::CrossThreadBind*` are provided as alternatives.
+`blink::Bind*` should be used to post tasks to the same thread and closures
+returned by it DCHECK that they run on the same thread.
+`blink::CrossThreadBind*` applies `CrossThreadCopier` to its arguments and
+creates a deep copy, so the resulting closure can run on a different thread.
 
 
 ## TODO(altimin): Document idle tasks
diff --git a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc
index 3902b67..fc49a5ea 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.cc
@@ -268,7 +268,8 @@
         chosen_task_queue->queue.get()->CreateQueueEnabledVoter());
   }
 
-  wtf_size_t voter_index = action.voter_id() % chosen_task_queue->voters.size();
+  blink::wtf_size_t voter_index =
+      action.voter_id() % chosen_task_queue->voters.size();
   chosen_task_queue->voters[voter_index]->SetVoteToEnable(action.enabled());
 }
 
@@ -301,7 +302,8 @@
   AutoLock lock(lock_);
   // We always want to have a default task queue.
   if (task_queues_.size() > 1) {
-    wtf_size_t queue_index = action.task_queue_id() % task_queues_.size();
+    blink::wtf_size_t queue_index =
+        action.task_queue_id() % task_queues_.size();
     task_queues_[queue_index].reset();
     task_queues_.erase(UNSAFE_TODO(task_queues_.begin() + queue_index));
   }
@@ -318,7 +320,7 @@
 
   AutoLock lock(lock_);
   if (!pending_tasks_.empty()) {
-    wtf_size_t task_index = action.task_id() % pending_tasks_.size();
+    blink::wtf_size_t task_index = action.task_id() % pending_tasks_.size();
     pending_tasks_[task_index]->weak_ptr_factory_.InvalidateWeakPtrs();
 
     // If it is already running, it is a parent task and will be deleted when
@@ -394,7 +396,7 @@
 
 void ThreadManager::DeleteTask(Task* task) {
   AutoLock lock(lock_);
-  wtf_size_t i = 0;
+  blink::wtf_size_t i = 0;
   while (i < pending_tasks_.size() && task != pending_tasks_[i].get()) {
     i++;
   }
diff --git a/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.cc b/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.cc
index f6ecd7ff..2c5d965 100644
--- a/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.cc
+++ b/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.cc
@@ -28,6 +28,8 @@
 
 namespace android {
 
+using blink::wtf_size_t;
+
 static const uint16_t CHAR_SOFT_HYPHEN = 0x00AD;
 
 // The following are structs that correspond to tables inside the hyb file
diff --git a/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.h b/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.h
index fee37c0..a002f0bc 100644
--- a/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.h
+++ b/third_party/blink/renderer/platform/text/hyphenation/hyphenator_aosp.h
@@ -44,7 +44,7 @@
   // 0 0], corresponding to "hy-phen".
   void hyphenate(blink::Vector<uint8_t>* result,
                  const uint16_t* word,
-                 wtf_size_t len);
+                 blink::wtf_size_t len);
 
   // pattern data is in binary format, as described in doc/hyb_file_format.md.
   // Note: the caller is responsible for ensuring that the lifetime of the
@@ -56,20 +56,22 @@
 
  private:
   // apply soft hyphens only, ignoring patterns
-  void hyphenateSoft(uint8_t* result, const uint16_t* word, wtf_size_t len);
+  void hyphenateSoft(uint8_t* result,
+                     const uint16_t* word,
+                     blink::wtf_size_t len);
 
   // Try looking up word in alphabet table, return false if any code units fail
   // to map.  Note that this methor writes len+2 entries into alpha_codes
   // (including start and stop).
   bool alphabetLookup(uint16_t* alpha_codes,
                       const uint16_t* word,
-                      wtf_size_t len);
+                      blink::wtf_size_t len);
 
   // calculate hyphenation from patterns, assuming alphabet lookup has already
   // been done
   void hyphenateFromCodes(uint8_t* result,
                           const uint16_t* codes,
-                          wtf_size_t len);
+                          blink::wtf_size_t len);
 
   // TODO: these should become parameters, as they might vary by locale, screen
   // size, and possibly explicit user control.
@@ -79,7 +81,7 @@
   // See also LONGEST_HYPHENATED_WORD in LineBreaker.cpp. Here the constant is
   // used so that temporary buffers can be stack-allocated without waste, which
   // is a slightly different use case. It measures UTF-16 code units.
-  static const wtf_size_t MAX_HYPHENATED_SIZE = 64;
+  static const blink::wtf_size_t MAX_HYPHENATED_SIZE = 64;
 
   raw_ptr<const uint8_t> patternData;
 
diff --git a/third_party/blink/renderer/platform/text/platform_locale.cc b/third_party/blink/renderer/platform/text/platform_locale.cc
index e20d57b..3706af4 100644
--- a/third_party/blink/renderer/platform/text/platform_locale.cc
+++ b/third_party/blink/renderer/platform/text/platform_locale.cc
@@ -346,7 +346,7 @@
                                         bool& is_negative,
                                         unsigned& start_index,
                                         unsigned& end_index) {
-  DCHECK_EQ(input.Find(IsASCIISpace), WTF::kNotFound);
+  DCHECK_EQ(input.Find(IsASCIISpace), kNotFound);
   start_index = 0;
   end_index = input.length();
   const auto adjust_for_affixes = [&](const String& prefix,
diff --git a/third_party/blink/renderer/platform/wtf/size_assertions.cc b/third_party/blink/renderer/platform/wtf/size_assertions.cc
index 618d1069..2936844 100644
--- a/third_party/blink/renderer/platform/wtf/size_assertions.cc
+++ b/third_party/blink/renderer/platform/wtf/size_assertions.cc
@@ -43,6 +43,8 @@
 
 namespace WTF {
 
+using blink::wtf_size_t;
+
 struct SameSizeAsRefCounted {
   uint32_t a;
   // Don't add anything here because this should stay small.
diff --git a/third_party/blink/renderer/platform/wtf/text/README.md b/third_party/blink/renderer/platform/wtf/text/README.md
index 3324385..1f94534 100644
--- a/third_party/blink/renderer/platform/wtf/text/README.md
+++ b/third_party/blink/renderer/platform/wtf/text/README.md
@@ -3,7 +3,7 @@
 _Everything you always wanted to know but were afraid to ask_
 
 This document covers the `String` type in Blink, often written with an
-explicit namespace as `WTF::String` to disambiguate from string
+explicit namespace as `blink::String` to disambiguate from string
 concepts or other types. It also briefly covers associated classes
 used for constructing strings (`StringBuilder`, `StringBuffer`), the
 internal `StringImpl` class, and the special `AtomicString` variant.
@@ -12,7 +12,7 @@
 
 ## Overview
 
-A `WTF::String` represents a sequence of zero or more Unicode code
+A `blink::String` represents a sequence of zero or more Unicode code
 points. A `String` can also represent one of two zero-length strings:
 the empty string and the null string. These correspond to "" and
 `null` in JavaScript, respectively. Both the empty and the null string
diff --git a/third_party/blink/renderer/platform/wtf/text/string_impl.h b/third_party/blink/renderer/platform/wtf/text/string_impl.h
index 3270851b..733aed2 100644
--- a/third_party/blink/renderer/platform/wtf/text/string_impl.h
+++ b/third_party/blink/renderer/platform/wtf/text/string_impl.h
@@ -799,7 +799,7 @@
 }
 
 // Search the `characters` span for `match_character` from the end of the span,
-// and returns the found index or WTF::kNotFound.
+// and returns the found index or kNotFound.
 //
 // If the optional `index` parameter is specified, this function searches from
 // characters[min(index, characters.size()-1)] to characters[0].
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc b/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
index 63021c0..8173e7f 100644
--- a/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
+++ b/third_party/blink/renderer/platform/wtf/text/wtf_string_test.cc
@@ -426,7 +426,7 @@
   TestMatcher matcher('t');
   // Unretained is safe because callback executes synchronously in Find().
   auto callback = BindRepeating(&TestMatcher::IsTarget, Unretained(&matcher));
-  EXPECT_EQ(WTF::kNotFound, test_string1.Find(callback));
+  EXPECT_EQ(kNotFound, test_string1.Find(callback));
   EXPECT_EQ(1U, test_string2.Find(callback));
 }
 
diff --git a/third_party/blink/renderer/platform/wtf/wtf_size_t.h b/third_party/blink/renderer/platform/wtf/wtf_size_t.h
index 7d4b6b8..47bf2b5 100644
--- a/third_party/blink/renderer/platform/wtf/wtf_size_t.h
+++ b/third_party/blink/renderer/platform/wtf/wtf_size_t.h
@@ -8,7 +8,7 @@
 #include <limits.h>
 #include <stdint.h>
 
-namespace WTF {
+namespace blink {
 
 // TLDR: size_t != wtf_size_t
 //
@@ -20,8 +20,8 @@
 // Matching the external API to match the internal API have a number of
 // required properties:
 //  - Internal storage for Vector and String are all uint32_t based.
-//  - Max heap allocation size is kMaxHeapObjectSize (much less than UINTMAX).
-//  - Consumers of APIs such as WTF::Vector may store their indices in some
+//  - Max heap allocation size is kMaxHeapObjectSize (much less than UINT_MAX).
+//  - Consumers of APIs such as blink::Vector may store their indices in some
 //    other storage and using size_t consumes extra data.
 //  - Checked_casts are too slow to use internally.
 //  - Conversion from wtf_size_t to size_t is always safe and static_casts
@@ -35,9 +35,6 @@
 using wtf_size_t = uint32_t;
 const wtf_size_t kNotFound = UINT_MAX;
 
-}  // namespace WTF
-
-using WTF::kNotFound;
-using WTF::wtf_size_t;
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_WTF_SIZE_T_H_
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 8ae29183..8c43cbccf 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
@@ -197,7 +197,7 @@
             'base::SplitOnceCallback',
 
             # //base/functional/callback.h is allowed, but you need to use
-            # WTF::Bind or WTF::BindRepeating to create callbacks in
+            # blink::BindOnce or blink::BindRepeating to create callbacks in
             # //third_party/blink/renderer.
             'base::BarrierCallback',
             'base::BarrierClosure',
@@ -928,8 +928,8 @@
             'hw::.+',
         ],
         'disallowed': [
-            ('base::Bind(Once|Repeating)',
-             'Use WTF::BindOnce or WTF::BindRepeating.'),
+            ('(base|WTF)::Bind(Once|Repeating)',
+             'Use blink::BindOnce or blink::BindRepeating.'),
             'base::BindPostTaskToCurrentDefault',
             _DISALLOW_NON_BLINK_MOJOM,
             _DISALLOW_CONTINUATION_DATA_,
@@ -2726,11 +2726,12 @@
 # GURL isn't namespace qualified and wouldn't match otherwise.
 # ContinuationPreservedEmbedder data is similarly hardcoded to restrict access
 # to the v8 APIs which would not otherwise match.
+# "WTF::" is hardcoded because the namespace is not lowercased.
 #
 # An example of an identifier that will be matched with this RE is
 # "base::BindOnce" or "performance_manager::policies::WorkingSetTrimData".
 _IDENTIFIER_WITH_NAMESPACE_RE = re.compile(
-    r'\b(?:(?:[a-z_][a-z0-9_]*::)+[A-Za-z_][A-Za-z0-9_]*|GURL|.*ContinuationPreservedEmbedderData.*)\b'
+    r'\b(?:(?:[a-z_][a-z0-9_]*::|WTF::)+[A-Za-z_][A-Za-z0-9_]*|GURL|.*ContinuationPreservedEmbedderData.*)\b'
 )
 
 # Different check which matches a non-empty sequence of lower-case
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage_test.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage_test.py
index ddc7019..9469490 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage_test.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage_test.py
@@ -101,6 +101,16 @@
                 'allowed': True,
                 'path': 'third_party/blink/renderer/core/scheduler/'
             },
+            {
+                'type': 'WTF::BindOnce',
+                'allowed': False,
+                'path': 'third_party/blink/renderer/'
+            },
+            {
+                'type': 'WTF::Vector',
+                'allowed': True,
+                'path': 'third_party/blink/renderer/platform/wtf/'
+            },
         ]
         for item in check_list:
             # Make sure that the identifier we're testing is parsed
diff --git a/third_party/blink/web_tests/OptimizationGuideExpectations b/third_party/blink/web_tests/OptimizationGuideExpectations
index 3d1557b0..9849e9a 100644
--- a/third_party/blink/web_tests/OptimizationGuideExpectations
+++ b/third_party/blink/web_tests/OptimizationGuideExpectations
@@ -13,8 +13,8 @@
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/add.https.any.html?gpu [ Crash ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.html?gpu [ Crash ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cast.https.any.html?gpu [ Crash ]
+virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/clamp.https.any.html?gpu [ Crash ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.html?gpu [ Crash ]
-virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any.html?gpu [ Crash ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gemm.https.any.html?gpu [ Crash ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/leaky_relu.https.any.html?gpu [ Crash ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/linear.https.any.html?gpu [ Crash ]
@@ -42,17 +42,18 @@
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/averagePool2d.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/batch_normalization.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/ceil.https.any.html?gpu [ Failure ]
-virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/clamp.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/concat.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cos.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cumulative_sum.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/div.https.any.html?gpu [ Failure ]
+virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/elu.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/erf.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/exp.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/expand.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/floor.https.any.html?gpu [ Failure ]
+virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherElements.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gru.https.any.html?gpu [ Failure ]
 virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/hard_sigmoid.https.any.html?gpu [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 38790fe..552812b8 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -45,7 +45,6 @@
 external/wpt/infrastructure/reftest/reftest_multiple_mismatch-0.html [ Failure ]
 external/wpt/infrastructure/reftest/reftest_multiple_mismatch-1.html [ Failure ]
 accessibility/slot-poison.html [ Failure ]
-editing/input/selectall-in-input-with-text-security.html [ Crash Failure ]
 wpt_internal/infrastructure/fail-with-nonexistent-subtest.html [ Failure ]
 
 # Expected to time out.
@@ -1458,6 +1457,9 @@
 # Failing on Win ARM
 crbug.com/379233932 [ Win11-arm64 ] external/wpt/ai/translator/* [ Skip Timeout ]
 
+# Disabled due to misconfigured PHP on win11-arm64 bots.
+crbug.com/433756870 [ Win11-arm64 ] http/tests/inspector-protocol/fetch/compressed-response-body.js [ Failure ]
+
 ### sheriff 2018-05-28
 
 crbug.com/767269 [ Win ] inspector-protocol/layout-fonts/cjk-ideograph-fallback-by-lang.js [ Failure Pass ]
@@ -2815,6 +2817,19 @@
 
 crbug.com/424798906 external/wpt/pointerevents/pointerevent_element_haspointercapture.html?touch [ Failure ]
 
+# [0722/141043.336307:FATAL:third_party/blink/renderer/core/css/style_traversal_root.cc:31] DCHECK failed: !document_element || (!root_node_ && root_type_ == RootType::kSingleRoot).
+crbug.com/433696404 external/wpt/dom/nodes/moveBefore/moveBefore-from-light-to-shadow.html [ Crash ]
+
+crbug.com/433565190 external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended.html [ Failure ]
+crbug.com/433565190 external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended.html [ Failure ]
+crbug.com/433565190 external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended.html [ Failure ]
+crbug.com/433565190 external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended.html [ Failure ]
+crbug.com/433565190 external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended.html [ Failure ]
+crbug.com/433565190 external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal.html [ Failure ]
+crbug.com/433565190 external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal.html [ Failure ]
+
+crbug.com/433687466 external/wpt/webrtc/RTCDataChannel-worker-GC.html [ Failure ]
+
 # ====== New tests from wpt-importer added here ======
 crbug.com/433297073 external/wpt/css/filter-effects/fecolormatrix-display-p3.html [ Failure ]
 crbug.com/433324167 external/wpt/html/canvas/element/text/2d.text.writingmode.html [ Failure ]
@@ -3006,7 +3021,6 @@
 crbug.com/431040244 [ Mac14 ] external/wpt/urlpattern/urlpattern.https.any.serviceworker.html [ Timeout ]
 crbug.com/431039950 [ Mac14 ] external/wpt/wasm/core/simd/simd_f32x4_arith.wast.js.html [ Crash ]
 crbug.com/431039950 [ Mac14 ] external/wpt/wasm/core/simd/simd_f64x2_arith.wast.js.html [ Crash ]
-crbug.com/431034520 [ Mac14 ] external/wpt/web-locks/bfcache/held.tentative.https.html [ Skip Timeout ]
 crbug.com/431040248 external/wpt/webdriver/tests/bidi/emulation/set_geolocation_override/user_contexts.py [ Failure ]
 crbug.com/431040244 [ Mac14 ] external/wpt/webrtc-identity/idlharness.https.window.html [ Timeout ]
 crbug.com/431038531 [ Mac14 ] external/wpt/websockets/stream/tentative/backpressure-send.any.serviceworker.html?wss [ Skip Timeout ]
@@ -3029,7 +3043,6 @@
 crbug.com/430091083 [ Win10.20h2 ] external/wpt/bluetooth/bidi/characteristic/readValue/event-is-fired.https.window.html [ Pass Timeout ]
 crbug.com/430091083 [ Win10.20h2 ] external/wpt/bluetooth/bidi/requestDevice/canonicalizeFilter/same-company-identifier.https.window.html [ Pass Timeout ]
 crbug.com/430091083 [ Win11-arm64 ] external/wpt/bluetooth/bidi/requestDevice/canonicalizeFilter/same-company-identifier.https.window.html [ Pass Timeout ]
-crbug.com/430125723 external/wpt/digital-credentials/get.tentative.https.html [ Failure ]
 crbug.com/430091580 [ Linux ] external/wpt/webdriver/tests/bidi/storage/get_cookies/filter.py [ Failure ]
 crbug.com/430091580 external/wpt/webdriver/tests/bidi/storage/set_cookie/cookie_same_site.py [ Failure ]
 crbug.com/430102835 virtual/scalefactor200/external/wpt/css/filter-effects/feconvolve-region-001.html [ Failure ]
@@ -8720,7 +8733,7 @@
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-016.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-017.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-018.html [ Failure ]
-crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-019.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-019.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-021.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-022.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-023.tentative.html [ Failure ]
@@ -8733,6 +8746,7 @@
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-031.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-032.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-033.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-034.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-001.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-002.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-003.tentative.html [ Failure ]
@@ -8752,11 +8766,13 @@
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-022.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-023.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-024.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-025.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-027.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-028.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-029.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-030.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-031.tentative.html [ Failure ]
+crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-032.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-033.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-034.tentative.html [ Failure ]
 crbug.com/40336192 virtual/disable-css-line-clamp/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-035.tentative.html [ Failure ]
@@ -9498,6 +9514,10 @@
 crbug.com/424918655 [ Mac ] external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image.html [ Failure Pass ]
 crbug.com/420596996 [ Win ] virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/parallel-dispatch.https.any.serviceworker.html?gpu [ Failure Pass ]
 
+# <object> loaded HTML doesn't receive drag and drop events
+crbug.com/426054999 external/wpt/html/editing/dnd/images/023.html [ Timeout ]
+crbug.com/426054999 external/wpt/html/editing/dnd/images/024.html [ Timeout ]
+
 # Gardener 2025-06-18
 crbug.com/425936609 external/wpt/resource-timing/tentative/document-initiated.html [ Pass Timeout ]
 
@@ -9593,7 +9613,5 @@
 # Gardener 2025-07-21
 crbug.com/419705502 [ Mac ] http/tests/devtools/elements/styles-2/nested-pseudo-elements.js [ Failure Pass ]
 
-crbug.com/427367145 http/tests/devtools/copy-network-request.js [ Failure Pass ]
-
 # Gardener 2025-07-23
-crbug.com/40253082 [ Mac14 ] virtual/controls-refresh-hc/fast/forms/color-scheme/select/select-multiple-appearance-basic.html [ Failure ]
\ No newline at end of file
+crbug.com/40253082 [ Mac14 ] virtual/controls-refresh-hc/fast/forms/color-scheme/select/select-multiple-appearance-basic.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 7f1adeb..75583067 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -647,8 +647,8 @@
     ],
     "exclusive_tests": "ALL",
     "args": [
-      "--enable-features=EnableBoundSessionCredentialsSoftwareKeysForManualTesting,DeviceBoundSessions",
-      "--disable-features=DeviceBoundSessionsRefreshQuota"
+      "--enable-features=EnableBoundSessionCredentialsSoftwareKeysForManualTesting,DeviceBoundSessions,DeviceBoundSessionsOriginTrialFeedback",
+      "--disable-features=DeviceBoundSessionsRefreshQuota,TrackingProtection3pcd"
     ],
     "expires": "never"
   },
@@ -1645,7 +1645,8 @@
     ],
     "bases": [
       "external/wpt/IndexedDB",
-      "storage/indexeddb"
+      "storage/indexeddb",
+      "wpt_internal/IndexedDB"
     ],
     "args": [
       "--enable-features=IdbSqliteBackingStore"
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 ae1f999..88270e1 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
@@ -625,7 +625,7 @@
       ]
      ],
      "anchor-display-none-crash.html": [
-      "bf513e391473d788fd2e06de7a2088e1d13939a1",
+      "4c02cd650a0e272a34809764c37bbf3628a8b31a",
       [
        null,
        {}
@@ -1716,7 +1716,7 @@
       ]
      ],
      "uncontained-oof-in-inline-after-break-000-crash.html": [
-      "4d301e497749ddf0d2bfca3a5976a9877b45cff8",
+      "262c8b99aaebab567dc6c6e9013f51a984770bdb",
       [
        null,
        {}
@@ -1868,7 +1868,7 @@
         ]
        ],
        "chrome-layout-root-crash.html": [
-        "e3e709a240bd870250b2747c94fe96880bdf52e3",
+        "55702868dce5dddb1212c2b08393f03a04bcfd4c",
         [
          null,
          {}
@@ -2092,7 +2092,7 @@
         ]
        ],
        "size-change-during-transition-crash.html": [
-        "80be45b8fd2c79ad5da2c611c50f3e9e0e35372f",
+        "3546ce4406a7781492e061f4c1eb7cf2698e29a2",
         [
          null,
          {}
@@ -2316,7 +2316,7 @@
        ]
       },
       "detach-locked-slot-children-crash.html": [
-       "409a9697b2f862c9fee90158194e3eb41c1c80bf",
+       "9b6ee9ce70b5f369dc2b111c82841a10b6da0f41",
        [
         null,
         {}
@@ -2512,7 +2512,7 @@
        ]
       ],
       "touch-action-beside-display-locked-fixedpos-iframe-crash.html": [
-       "920305c14dd98b2f435a92217c689ec8601fbbad",
+       "5a7a41b94905975acce7f53fecfb5c5bcf3b16b0",
        [
         null,
         {}
@@ -3288,7 +3288,7 @@
       ]
      ],
      "list-item-counter-crash.html": [
-      "fc8a38c628026dc190d81e27150d8ebabb130ae2",
+      "27476ff7af0e362a84fecccf3b95cb35be952d4f",
       [
        null,
        {}
@@ -3460,7 +3460,7 @@
        ]
       ],
       "chrome-bug-1301281.html": [
-       "0c34e0889020d28cbf45254b2b853453de0f4cac",
+       "bb4f1fc55b15c953fca0e8f955a22412677aba82",
        [
         null,
         {}
@@ -3530,7 +3530,7 @@
        ]
       ],
       "floated-input-in-inline-next-column.html": [
-       "1b84cd3d99a723e33301f87db3a3933ac33c8cf2",
+       "f1ada47baa22290e0fe39434dae24d7b7dd2802b",
        [
         null,
         {}
@@ -3558,7 +3558,7 @@
        ]
       ],
       "inline-float-parallel-flow.html": [
-       "06e80f1cd847dac2beb8fa6133723cdc906b362a",
+       "5280b8a63c860c631d01434f43709e4c2131d5de",
        [
         null,
         {}
@@ -3593,14 +3593,14 @@
        ]
       ],
       "move-linebreak-to-different-column.html": [
-       "abe83ca19489dcbbdccc379c295fb391ca5b24fb",
+       "d87881c35096394aeda210d47f1a7619cab00e32",
        [
         null,
         {}
        ]
       ],
       "move-newline-pre-text.html": [
-       "13833ae946e25d68f5d70134cf0808dc91d001cb",
+       "d63f919662b281629045f10b3e78672d814d658b",
        [
         null,
         {}
@@ -3859,7 +3859,7 @@
        ]
       ],
       "oof-in-additional-column-before-spanner.html": [
-       "afdeabe174ef39f10d2aa2db152fbfb32e86df72",
+       "fbfa04468c3b1a5ef35bcb81bbb10df0a5e5d6fc",
        [
         null,
         {}
@@ -4287,7 +4287,7 @@
       ]
      ],
      "subpixel-scroll-crash.html": [
-      "5a429085052352093bfe135c00103f5953792deb",
+      "254dfaf8735e90ea3580a999a5a40fdff21583a8",
       [
        null,
        {}
@@ -4507,14 +4507,14 @@
       ]
      ],
      "scroll-marker-dynamic-crash.html": [
-      "22c5b7d2299b8ebef349b393da82a88e224fbff9",
+      "8512ef5a9fdc4ddf5c00c3b6305183a5b1441e92",
       [
        null,
        {}
       ]
      ],
      "scroll-marker-focus-scroll-crash.html": [
-      "97b3be1e8fb24c003cf0dec4c8cdc89da18b4f70",
+      "ed92b216f63e504efc4b26a51a2a2315e21ffd64",
       [
        null,
        {
@@ -4523,14 +4523,14 @@
       ]
      ],
      "scroll-marker-with-content-visibility-hidden-ancestor-crash.html": [
-      "451e9e9709a9a5b1bc2c371884249a26cfb6e391",
+      "4f3c277ca85756c87b8c89fd52c2b176f525518e",
       [
        null,
        {}
       ]
      ],
      "scroll-marker-with-content-visibility-hidden-crash.html": [
-      "7e6fee214ca5db129a52564b4fbf0fd818fc1091",
+      "fd194c53dccff48d863ebcbc3663996565740c22",
       [
        null,
        {}
@@ -4558,7 +4558,7 @@
       ]
      ],
      "scroll-markers-resize-crash.html": [
-      "64d45fa55c85a3a6666722fa09541165d2c0b1b8",
+      "8a162673d0709ddcc956daa276bfebeab9b57b72",
       [
        null,
        {}
@@ -4695,7 +4695,7 @@
      ],
      "overlay": {
       "overlay-popover-backdrop-crash.html": [
-       "f59fc5db4ae3fbbd383a1a9a7dfccf9597229119",
+       "1180dd6926209835e10b94173a77a802a713f8ff",
        [
         null,
         {}
@@ -6073,7 +6073,7 @@
        ]
       ],
       "reload-crash.html": [
-       "a2bf11b31dc28129382837d7dd75f37544a51911",
+       "c28bd36030b25624dc0edafd08cead01e7a2e989",
        [
         null,
         {}
@@ -6088,7 +6088,7 @@
       ]
      ],
      "root-element-display-none-crash.html": [
-      "d228be8581a711f2edba4e833f4e813f9d8b362b",
+      "dfcac9eb7baa33e92a16e11c0350f046a743ebc7",
       [
        null,
        {}
@@ -6109,7 +6109,7 @@
       ]
      ],
      "root-reconstruct-frame-tree-crash.html": [
-      "bff9a1629a1cdcdc2aac2bd5c961a47823e3f5a7",
+      "108f3c1fd9e80dfb94035ff780c7578764469304",
       [
        null,
        {}
@@ -6874,14 +6874,14 @@
       ]
      ],
      "caret-display-list-002.html": [
-      "23f0496efd60a8be111de489ca92de4a34874484",
+      "972824c12c75cc144e5f1d889bd15c83ccec9668",
       [
        null,
        {}
       ]
      ],
      "caret-display-list.html": [
-      "f7c7a740e18925dba2da8704700ee23a5359921f",
+      "0535224ac753c38f92b7e2e1d9f1eca31df433c4",
       [
        null,
        {}
@@ -7035,7 +7035,7 @@
       ]
      ],
      "designMode-caret-change.html": [
-      "be80afd4ab8a474572d1732baecdcb1f052c57fb",
+      "685fd17dfafd9a6257fad89f694d6a9184cf0e3f",
       [
        null,
        {}
@@ -7858,7 +7858,7 @@
       ]
      ],
      "chrome-1312699.html": [
-      "c783b0d9cc9634654f59654945a1bdcf38539cc8",
+      "180f3664e6132a2a45205499883f9a6994371bbb",
       [
        null,
        {
@@ -7945,7 +7945,7 @@
       "manual": {
        "the-offscreen-canvas": {
         "offscreencanvas-worker-font-load-crash.html": [
-         "1baf7847deab9f46cce410f39087b3f9db389ca6",
+         "884daa758bf9c80720ffa39dcadc5996fbdd1cca",
          [
           null,
           {}
@@ -9926,14 +9926,14 @@
    "selection": {
     "crashtests": {
      "selectall-and-find-svg-text-on-selectstart.html": [
-      "9f9dfbc9384aa5a330a4304f9c586f62983564ca",
+      "b49dee225fcda5c14bd840973024a0d6c5e80a42",
       [
        null,
        {}
       ]
      ],
      "selection-clip-crash.html": [
-      "66d10b47424226f79f676a87288b667aed2911e1",
+      "4179356594414a942dfc25875f6b575ea36325ae",
       [
        null,
        {}
@@ -9975,7 +9975,7 @@
       ]
      ],
      "selection-modify-line-boundary-around-shadow.html": [
-      "bfca0402a7096a61b17d8dfa68f736f76fd3dcfa",
+      "13faa4ed3dacdc11beb26700fc4893b3e181114a",
       [
        null,
        {}
@@ -10229,14 +10229,14 @@
       ]
      },
      "end-of-time-001-crash.html": [
-      "bd38d93161414ed9b19750805b313972b40703af",
+      "96821bd8bb8294a104582e5849a3afb0e2c583a1",
       [
        null,
        {}
       ]
      ],
      "end-of-time-002-crash.html": [
-      "6951820f51dc8614bf65fde71265384910487bfe",
+      "58fbf98676f3eba4be1b8111cfa3aba4fe2b29c8",
       [
        null,
        {}
@@ -115902,8 +115902,21 @@
       ]
      },
      "japanese-formal": {
+      "counter-japanese-formal-extended.html": [
+       "62357c63952d67d91f046c8f7390c8aa6d74b0c8",
+       [
+        null,
+        [
+         [
+          "/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "counter-japanese-formal.html": [
-       "6558514755197c58f2d5d063d363bbe295767288",
+       "c67ce6cd21ed5c8d49e7549420684110add8d947",
        [
         null,
         [
@@ -115986,8 +115999,21 @@
       ]
      },
      "japanese-informal": {
+      "counter-japanese-informal-extended.html": [
+       "8a72eaa6b71e8d24570477e6c701261e873fb62c",
+       [
+        null,
+        [
+         [
+          "/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "counter-japanese-informal.html": [
-       "5263e99944181db28872558950008124175142b8",
+       "4493545b86264684dde905c4e4ae34d5f3458982",
        [
         null,
         [
@@ -116234,8 +116260,21 @@
       ]
      },
      "korean-hangul-formal": {
+      "counter-korean-hangul-formal-extended.html": [
+       "9dbbc6c3dd46123f060c9f6562f08bba60b490e2",
+       [
+        null,
+        [
+         [
+          "/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "counter-korean-hangul-formal.html": [
-       "468e0b87b15f9796edbbabd17dc915110ae71ed8",
+       "cff3e72ea04431f8074d6c0afe6c301297c08686",
        [
         null,
         [
@@ -116318,8 +116357,21 @@
       ]
      },
      "korean-hanja-formal": {
+      "counter-korean-hanja-formal-extended.html": [
+       "e7d4e1f3c40499c0915e118f01d829786f688920",
+       [
+        null,
+        [
+         [
+          "/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "counter-korean-hanja-formal.html": [
-       "c6fb66a733dce05f1d743b332cd40f54da588519",
+       "6aa00234763fdc0ed12dbef94a04197b10b3faee",
        [
         null,
         [
@@ -116402,8 +116454,21 @@
       ]
      },
      "korean-hanja-informal": {
+      "counter-korean-hanja-informal-extended.html": [
+       "d575047f25f2cd7eb7116bfb2831847ba1c7ebd1",
+       [
+        null,
+        [
+         [
+          "/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "counter-korean-hanja-informal.html": [
-       "dc16c886dc7d0a3017c123beb410bb9fac7a3498",
+       "e967daed81d48fd61041ffa633067d219fef0890",
        [
         null,
         [
@@ -116924,7 +116989,7 @@
      },
      "simp-chinese-formal": {
       "counter-simp-chinese-formal.html": [
-       "29bf9520a0c84a8709e40f4623e67bc0e488125d",
+       "2fced35fc6e0e01b0524241af55bcd96bc0dcad3",
        [
         null,
         [
@@ -117008,7 +117073,7 @@
      },
      "simp-chinese-informal": {
       "counter-simp-chinese-informal.html": [
-       "2cf2984972fc5fdd71405c5042a77651ef68a4f8",
+       "2293281d73d36999c0f2d1ebda3ab2adb47ccfcd",
        [
         null,
         [
@@ -117256,7 +117321,7 @@
      },
      "trad-chinese-formal": {
       "counter-trad-chinese-formal.html": [
-       "4829d3da42f2a43e42b69e38793f6f1bffb7848d",
+       "2953afdd74bd499707e2bd3bdb7e055732cc24b0",
        [
         null,
         [
@@ -117340,7 +117405,7 @@
      },
      "trad-chinese-informal": {
       "counter-trad-chinese-informal.html": [
-       "8fdc1c6cbbaaa50155968e3cbf85667caa8cbc6f",
+       "a01074dbfad4b1f68f9987ead73fbc1ce10f8cf5",
        [
         null,
         [
@@ -162232,6 +162297,19 @@
          {}
         ]
        ],
+       "clip-path-animation-retarget.html": [
+        "1e3624e73742ac29ed35d04b1750fcb71fad3ab3",
+        [
+         null,
+         [
+          [
+           "/css/css-masking/clip-path/animations/clip-path-animation-retarget-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "clip-path-animation-revert-layer.html": [
         "cc23c96e2ee76f75cb30280320da3ee9e4cbdb1b",
         [
@@ -162258,6 +162336,19 @@
          {}
         ]
        ],
+       "clip-path-animation-set-effect.html": [
+        "a3fae2733d0a6050ca60409a11b69042347adf74",
+        [
+         null,
+         [
+          [
+           "/css/css-masking/clip-path/animations/clip-path-animation-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "clip-path-animation-svg-zoom.html": [
         "0accfd2102b72b196a4cfa987f88a5e31223d249",
         [
@@ -162355,6 +162446,19 @@
          {}
         ]
        ],
+       "clip-path-animation-zero-duration.html": [
+        "45afe41c35e04a9417193b38d251cdf49bb03455",
+        [
+         null,
+         [
+          [
+           "/css/css-masking/clip-path/animations/clip-path-animation-zero-duration-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
        "clip-path-animation-zoom.html": [
         "89641240f67bfd468a260bda514ec9b91914ff0d",
         [
@@ -279225,6 +279329,35 @@
        }
       ]
      ],
+     "backdrop-filter-box-shadow.html": [
+      "097b279ddd423be4d434b237da4f2bc10a458e0a",
+      [
+       null,
+       [
+        [
+         "/css/filter-effects/reference/backdrop-filter-box-shadow-ref.html",
+         "=="
+        ]
+       ],
+       {
+        "fuzzy": [
+         [
+          null,
+          [
+           [
+            0,
+            1
+           ],
+           [
+            0,
+            10000
+           ]
+          ]
+         ]
+        ]
+       }
+      ]
+     ],
      "backdrop-filter-clip-radius-zoom.html": [
       "960aafca92da0e095241ab559ab72b85cbf8e15e",
       [
@@ -285838,7 +285971,7 @@
       ]
      ],
      "featureless-004.html": [
-      "d0ea23e560f2e7697f4727f3145c9b4af035f042",
+      "4ff1fe7d1649be74e3a4fe7b81462264628bedc7",
       [
        null,
        [
@@ -324683,19 +324816,19 @@
       []
      ],
      "failures_Ed448.https.any-expected.txt": [
-      "df020a88c18215dd8e4bbc7c4c6ac7edcc56d33e",
+      "9e773ae68af00710e3ef5a44a921d178d7c5d4df",
       []
      ],
      "failures_Ed448.https.any.worker-expected.txt": [
-      "df020a88c18215dd8e4bbc7c4c6ac7edcc56d33e",
+      "9e773ae68af00710e3ef5a44a921d178d7c5d4df",
       []
      ],
      "failures_X448.https.any-expected.txt": [
-      "f4517ad311fd7d2b1c7716e5642ae8bbf1083143",
+      "53b8a7e9c387fc3e374b0a595d53ae66b007af36",
       []
      ],
      "failures_X448.https.any.worker-expected.txt": [
-      "f4517ad311fd7d2b1c7716e5642ae8bbf1083143",
+      "53b8a7e9c387fc3e374b0a595d53ae66b007af36",
       []
      ],
      "successes.js": [
@@ -324735,19 +324868,19 @@
       []
      ],
      "successes_Ed448.https.any-expected.txt": [
-      "8268ad2ed7ab2ad28af5e3abe56c3ff91a28bb7a",
+      "30f29525521455688b1c57973eb48f039224b4cc",
       []
      ],
      "successes_Ed448.https.any.worker-expected.txt": [
-      "8268ad2ed7ab2ad28af5e3abe56c3ff91a28bb7a",
+      "30f29525521455688b1c57973eb48f039224b4cc",
       []
      ],
      "successes_X448.https.any-expected.txt": [
-      "f51f7f38c4f1a27567fc68f1aab9beeccf499588",
+      "b47aa9dd80efc5d50eeba04e8040fc5696a0a68d",
       []
      ],
      "successes_X448.https.any.worker-expected.txt": [
-      "f51f7f38c4f1a27567fc68f1aab9beeccf499588",
+      "b47aa9dd80efc5d50eeba04e8040fc5696a0a68d",
       []
      ]
     },
@@ -324789,19 +324922,19 @@
       []
      ],
      "okp_importKey_failures_Ed448.https.any-expected.txt": [
-      "8018545dd98ea1bea94c27681a70f161aa9a34a7",
+      "59e83f578305511158c2b951884d97cfa3eccbd2",
       []
      ],
      "okp_importKey_failures_Ed448.https.any.worker-expected.txt": [
-      "8018545dd98ea1bea94c27681a70f161aa9a34a7",
+      "59e83f578305511158c2b951884d97cfa3eccbd2",
       []
      ],
      "okp_importKey_failures_X448.https.any-expected.txt": [
-      "6b6a855094b5800e2f5ca214d454e250eb195a18",
+      "903dd31e8abc800680c6856b78046d2c2acd05a4",
       []
      ],
      "okp_importKey_failures_X448.https.any.worker-expected.txt": [
-      "6b6a855094b5800e2f5ca214d454e250eb195a18",
+      "903dd31e8abc800680c6856b78046d2c2acd05a4",
       []
      ],
      "okp_importKey_failures_fixtures.js": [
@@ -344419,8 +344552,12 @@
       ]
      },
      "japanese-formal": {
+      "counter-japanese-formal-extended-ref.html": [
+       "e7dc0f5a02db157702cccf831acf21268e95ac3f",
+       []
+      ],
       "counter-japanese-formal-ref.html": [
-       "674823030fa6607f5985c91c9447618aaa9ba39f",
+       "d7a8474c1055e4f2bb7ea34aff8bf20f9c8a723e",
        []
       ],
       "css3-counter-styles-047-ref.html": [
@@ -344449,8 +344586,12 @@
       ]
      },
      "japanese-informal": {
+      "counter-japanese-informal-extended-ref.html": [
+       "5957cd240a50fcf076d50fd72a12e71b2dab29da",
+       []
+      ],
       "counter-japanese-informal-ref.html": [
-       "a08a63631b8594200f57c2613b15ea2310478d2d",
+       "f5e9376b7eeb5bed3c5b70874376936774ae76be",
        []
       ],
       "css3-counter-styles-042-ref.html": [
@@ -344535,8 +344676,12 @@
       ]
      },
      "korean-hangul-formal": {
+      "counter-korean-hangul-formal-extended-ref.html": [
+       "3adaa814ab8d94828f5aa5eac8ffe7cecd02ccb2",
+       []
+      ],
       "counter-korean-hangul-formal-ref.html": [
-       "641fa5de1e6899893631f4340420449b27b5eb1c",
+       "8beab9aa38704c1516d85e807fc1315506804d7f",
        []
       ],
       "css3-counter-styles-052-ref.html": [
@@ -344565,8 +344710,12 @@
       ]
      },
      "korean-hanja-formal": {
+      "counter-korean-hanja-formal-extended-ref.html": [
+       "a5b55ccd19ee48016eb286e3198f2181543b0392",
+       []
+      ],
       "counter-korean-hanja-formal-ref.html": [
-       "da1f8a4813de6129dab366675fd1dc35fe9ea94e",
+       "ba4e39d1df76e7397de113325714755967c43ee9",
        []
       ],
       "css3-counter-styles-062-ref.html": [
@@ -344595,8 +344744,12 @@
       ]
      },
      "korean-hanja-informal": {
+      "counter-korean-hanja-informal-extended-ref.html": [
+       "18e6114d662f5dc495e7e3bf56bd8e5113cf5c22",
+       []
+      ],
       "counter-korean-hanja-informal-ref.html": [
-       "1a7286f4da23246b32f2d25bfef2aeb654de91de",
+       "5ddae77c745bf061a2ab6341226201cc253f1866",
        []
       ],
       "css3-counter-styles-057-ref.html": [
@@ -344768,7 +344921,7 @@
      },
      "simp-chinese-formal": {
       "counter-simp-chinese-formal-ref.html": [
-       "9a39f67426775ad69b72971b5de5b1bf14e19cee",
+       "4a3b7f25568c21b2bb8002410f46e4865b2d806c",
        []
       ],
       "css3-counter-styles-076-ref.html": [
@@ -344798,7 +344951,7 @@
      },
      "simp-chinese-informal": {
       "counter-simp-chinese-informal-ref.html": [
-       "adc0a4c6c618032e84eab932f6a73d497b745a64",
+       "e2272c69923dbb1f7815beb6ab9ddaa4688a1a36",
        []
       ],
       "css3-counter-styles-071-ref.html": [
@@ -344884,7 +345037,7 @@
      },
      "trad-chinese-formal": {
       "counter-trad-chinese-formal-ref.html": [
-       "8437f83142aec95c8e7ba21e556641ccb2c18760",
+       "d903809f6a0078a1fbce813a8b878e50cbfbd326",
        []
       ],
       "css3-counter-styles-086-ref.html": [
@@ -344914,7 +345067,7 @@
      },
      "trad-chinese-informal": {
       "counter-trad-chinese-informal-ref.html": [
-       "2e156901ed7ad997c1cc4fba699ad8376a3ab90f",
+       "e8f11fcd6d85e497bfcc46d6c9759317daa71b59",
        []
       ],
       "css3-counter-styles-081-ref.html": [
@@ -347672,10 +347825,6 @@
       "ef5513afe84d6b8b2f03dd0c601e32098a67c6ac",
       []
      ],
-     "font-face-style-normal-expected.txt": [
-      "ce8c6b56f46d77bd5392b0e4d7559c6022f27351",
-      []
-     ],
      "font-face-unicode-range-2-ref.html": [
       "a338b8eb0f5acc25b7aa2590d96ba5e33c792111",
       []
@@ -348607,10 +348756,6 @@
        "9966da1929c09a29a7f69148b988764ad1a44795",
        []
       ],
-      "font-feature-settings-computed-expected.txt": [
-       "84f076994fba9811468d0e6378add5c7e6310fd4",
-       []
-      ],
       "font-language-override-computed-expected.txt": [
        "0615808d5b8fb307a7ba99cb920667e5dcfc4997",
        []
@@ -348628,7 +348773,7 @@
        []
       ],
       "font-style-valid-expected.txt": [
-       "e7cb35d7e3a29673a478b5771b8dd64c6cd3b855",
+       "cf535095666906571b50a0e27ab7d2b837de11d8",
        []
       ],
       "font-synthesis-computed-expected.txt": [
@@ -355026,7 +355171,7 @@
        []
       ],
       "at-font-face-descriptors-expected.txt": [
-       "f2e573c02846354f9ede050da982e228cacc6043",
+       "1111244997de15afec52abf4881934fa81fc2af9",
        []
       ],
       "font-descriptor-range-reversed-ref.html": [
@@ -360452,6 +360597,10 @@
         "b548c5d590edeef0d7aa8a8b4461fed72d2460c7",
         []
        ],
+       "clip-path-animation-retarget-ref.html": [
+        "b1e9ef5764029a5bd0645b71eb2ece265e340281",
+        []
+       ],
        "clip-path-animation-svg-ref.html": [
         "6cc3b4d58bd2ce7c1c9aef9df84dbff47d783f34",
         []
@@ -360468,6 +360617,10 @@
         "afc8c855617b9777f05c6d42ba2682e077dfb663",
         []
        ],
+       "clip-path-animation-zero-duration-ref.html": [
+        "587226fa5d5914ce61ad4c251008ed18c420633d",
+        []
+       ],
        "clip-path-animation-zoom-ref.html": [
         "99126195a13b6e09a9e6080277a454d19c8576bf",
         []
@@ -366306,7 +366459,7 @@
      ],
      "computedstyle": {
       "block-level-replaced-elements-affected-by-block-step-size-expected.txt": [
-       "475a8506a629843dfe63a895bdfd285f3a527590",
+       "19375a7c7d59e39e8135b367e5b5bf7b0dac5e3c",
        []
       ]
      },
@@ -373727,17 +373880,13 @@
        "bc8409c24dd3ea29cd8ed34d071e9e1102860b30",
        []
       ],
-      "text-decoration-computed-expected.txt": [
-       "36722111d5268a4f35b73a368a819f7a737478d6",
-       []
-      ],
-      "text-decoration-valid-expected.txt": [
-       "9dd2d506bbfb822d00f39b3cbcd9fd77d86cfd1e",
-       []
-      ],
       "text-emphasis-position-valid-expected.txt": [
        "08d5ae4e8f6cb0fd5794ccdb719f90ee41c74a15",
        []
+      ],
+      "text-emphasis-style-computed-expected.txt": [
+       "bed7817c4e8641061fe6b2eac8e764cfad8be73a",
+       []
       ]
      },
      "reference": {
@@ -374180,10 +374329,6 @@
       "d20e4e49b3854e22d3dc4822bc16ffa920799911",
       []
      ],
-     "text-decoration-serialization.tentative-expected.txt": [
-      "26b55bee35d38fbf164a62c1608f37ea6a9289b6",
-      []
-     ],
      "text-decoration-skip-ink-expected.txt": [
       "b6c300add98e7d2d0f3b046a4b44b957cf598c3b",
       []
@@ -378406,6 +378551,10 @@
       "152dc9713518c4c1a4b7ff432787ddb17e973736",
       []
      ],
+     "random-in-keyframe-expected.txt": [
+      "e0f4a99960fcc88db5d90b006ab6464d4d0e25ae",
+      []
+     ],
      "random-serialize.tentative-expected.txt": [
       "62eb81a6779f54ab7f8a0b0bba7c7413d300d731",
       []
@@ -383851,6 +384000,10 @@
        "6cf03dde8c56c5c8e5b27623ea211ba8e6d2ad80",
        []
       ],
+      "backdrop-filter-box-shadow-ref.html": [
+       "13bf81655c3096a6eedf47f86d0398535e8b4eeb",
+       []
+      ],
       "backdrop-filter-clip-rect-2-ref.html": [
        "f12e88515fe9d3d845599273054803b7f782dd5a",
        []
@@ -386317,10 +386470,6 @@
      "6555add5b5d7d45ebc1004d1d27c329aaf6f55e8",
      []
     ],
-    "digital-credential-user-agent-allows-protocol.https-expected.txt": [
-     "9660e76523e70ca8128dfe4a2e43944f0894e0c6",
-     []
-    ],
     "digital-credentials-static-methods.tentative.https-expected.txt": [
      "5c4a3b206c3f733dc0fe3e9255e7698d30f4b028",
      []
@@ -386571,7 +386720,7 @@
       []
      ],
      "safari.md": [
-      "eed52254718922b000abd30273a50d56ce84d35a",
+      "afbbeb67c699118f626f08f776d99aae547b5e1e",
       []
      ],
      "testing-polyfills.md": [
@@ -386984,10 +387133,6 @@
       "cb89704f1f7e3b4ec008e3fabba4a8a2dce51c6b",
       []
      ],
-     "DOMImplementation-createDocument-expected.txt": [
-      "58edcad580d2ce025ea343aac264f19ce73812a0",
-      []
-     ],
      "DOMImplementation-createHTMLDocument.js": [
       "3e7e9aa9b787a1f628043b43dc187c406eb33e7f",
       []
@@ -387216,10 +387361,6 @@
        []
       ]
      },
-     "Document-createElementNS-expected.txt": [
-      "6ca2a675ff0fe087262ed71df3d507cdcab265c1",
-      []
-     ],
      "Document-createElementNS.js": [
       "21902ec504e76f775ac36b9655b4c54e87e8c762",
       []
@@ -387358,10 +387499,6 @@
       "a95529ab39cdcbc19c627d1b1dc998ac426c5e9b",
       []
      ],
-     "name-validation-expected.txt": [
-      "477a4c077448844d608fa692d7c08114c30870a4",
-      []
-     ],
      "pre-insertion-validation-hierarchy.js": [
       "6ef2576df2c70bf6d13509c92071541c8e5bb5c7",
       []
@@ -387799,7 +387936,7 @@
       []
      ],
      "insertparagraph.js": [
-      "8e72eb5c506248d8191e69a0036d194d398d66a4",
+      "6583152e1776bc7c38552114035f9da480cab402",
       []
      ],
      "inserttext.js": [
@@ -410362,7 +410499,7 @@
        ],
        "resources": {
         "focus-utils.js": [
-         "040263064115a7bfa5d79beadbcc068a2eec114d",
+         "4e5c5b00e7a951b485430b198924ed6c9f6864c7",
          []
         ],
         "image-submit-click.html": [
@@ -410695,7 +410832,7 @@
         ],
         "resources": {
          "customizable-select-in-page.css": [
-          "deb080b4756cf51d2ece9d2b132e9fff6ccd6f7c",
+          "1e3a50e30abc4a278f097472779d941bd7015bfb",
           []
          ],
          "customizable-select-in-page.js": [
@@ -416033,7 +416170,7 @@
         []
        ],
        "canvas-background.html.ini": [
-        "198b67c43cd9ee8ff0eef85ea7c3ee41d0689073",
+        "8e79877c30dd27759acb8fded9d2de322fcf8246",
         []
        ],
        "document-fonts-ready.html.ini": [
@@ -416197,7 +416334,7 @@
         []
        ],
        "http2-websocket.sub.h2.any.js.ini": [
-        "74470b82c2441e7df6090e29e2e9e16a75065881",
+        "d9a0e76368cf0513b51ab100ae11c3f53c13a04e",
         []
        ],
        "secure-context.https.any.js.ini": [
@@ -416361,7 +416498,7 @@
         []
        ],
        "file_upload.sub.html.ini": [
-        "ce88c728e034a87334b2f9b275fbc31160f32222",
+        "8b7c0f25e6a3bc8d92cf4066c68fbaf3f3d1990d",
         []
        ],
        "generate_test_report.html.ini": [
@@ -416409,7 +416546,7 @@
       },
       "window": {
        "minimize-1.html.ini": [
-        "2e3ac5190f397acff96227d8b80042b62e1869ae",
+        "5566efc77404859bf0f0a64adece17bf8730a34d",
         []
        ]
       }
@@ -427441,10 +427578,18 @@
      "cdcab0e70535014219e2da44a28615004db6a1a4",
      []
     ],
+    "authentication-accepted.https-expected.txt": [
+     "cc41cd292b6c7f76c9201b129edf70dd79fea592",
+     []
+    ],
     "authentication-requires-user-activation.https-expected.txt": [
      "19b11cfe3c365baf22b767ce7784ea17a4a0fbe8",
      []
     ],
+    "constructor-validate-payment-method-data.https-expected.txt": [
+     "0d94a62de0bee382bc52a48aa1883558e21bce16",
+     []
+    ],
     "resources": {
      "iframe-authenticate.html": [
       "828e81f60d79abb341779dacc10030521b825dc8",
@@ -431558,9 +431703,17 @@
        []
       ],
       "resources": {
+       "large-text.css": [
+        "d1dc63e2918ec52720083f631785670e6a743cdd",
+        []
+       ],
        "other_window.html": [
         "406d39c3691853a03731287b2a02f215dcbf721c",
         []
+       ],
+       "x-large-text.css": [
+        "2e2c17b37bd09e8ad9d41e567483966f942b759b",
+        []
        ]
       }
      }
@@ -437588,7 +437741,7 @@
        []
       ],
       "accumulation-per-property-002-expected.txt": [
-       "132429d7098d1911e479919f2e07c985a6e9b74c",
+       "c06b654a1f0adbc286b528eb1e935874fb62ce9a",
        []
       ],
       "addition-per-property-001-expected.txt": [
@@ -437596,7 +437749,7 @@
        []
       ],
       "addition-per-property-002-expected.txt": [
-       "86034cfdda87e9233c5312dbab97025f722a6e3f",
+       "64682d589996bdf1e9fa5ec481ef42ff06f35de1",
        []
       ],
       "interpolation-per-property-001-expected.txt": [
@@ -437604,7 +437757,7 @@
        []
       ],
       "interpolation-per-property-002-expected.txt": [
-       "4138b9fe3cfe97f5a52e06995e80b18baaee39d8",
+       "b6734d945426c656c44c4bac181f428ef3aeadf5",
        []
       ],
       "property-list.js": [
@@ -441730,7 +441883,7 @@
      []
     ],
     "supported-stats.https-expected.txt": [
-     "6ae34466677c6565baecdb7c4df5ad9c3da71bf8",
+     "f15bbf4210dcf3889a9b656e1a9b9a4cb50acae1",
      []
     ]
    },
@@ -465210,10 +465363,10 @@
        }
       ]
      ],
-     "cfrg_curves_bits_curve448.https.any.js": [
+     "cfrg_curves_bits_curve448.tentative.https.any.js": [
       "32485c68107e5c0aa94264caf1a097909723d173",
       [
-       "WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any.html",
+       "WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -465232,7 +465385,7 @@
        }
       ],
       [
-       "WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any.worker.html",
+       "WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -465292,10 +465445,10 @@
        }
       ]
      ],
-     "cfrg_curves_keys_curve448.https.any.js": [
+     "cfrg_curves_keys_curve448.tentative.https.any.js": [
       "b34e366376a70f6bf7628d9fa62c42e5201a053f",
       [
-       "WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any.html",
+       "WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -465314,7 +465467,7 @@
        }
       ],
       [
-       "WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any.worker.html",
+       "WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -467628,10 +467781,10 @@
        }
       ]
      ],
-     "failures_Ed448.https.any.js": [
+     "failures_Ed448.tentative.https.any.js": [
       "b25dcd14909410125fe147a883e98f41ab281b96",
       [
-       "WebCryptoAPI/generateKey/failures_Ed448.https.any.html",
+       "WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -467655,7 +467808,7 @@
        }
       ],
       [
-       "WebCryptoAPI/generateKey/failures_Ed448.https.any.worker.html",
+       "WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -467934,10 +468087,10 @@
        }
       ]
      ],
-     "failures_X448.https.any.js": [
+     "failures_X448.tentative.https.any.js": [
       "455e260d1fe920b9d7982f1a91abd56bf842ecee",
       [
-       "WebCryptoAPI/generateKey/failures_X448.https.any.html",
+       "WebCryptoAPI/generateKey/failures_X448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -467961,7 +468114,7 @@
        }
       ],
       [
-       "WebCryptoAPI/generateKey/failures_X448.https.any.worker.html",
+       "WebCryptoAPI/generateKey/failures_X448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -468398,10 +468551,10 @@
        }
       ]
      ],
-     "successes_Ed448.https.any.js": [
+     "successes_Ed448.tentative.https.any.js": [
       "8e37f57b244b582149261003109e0c2c199d6936",
       [
-       "WebCryptoAPI/generateKey/successes_Ed448.https.any.html",
+       "WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -468429,7 +468582,7 @@
        }
       ],
       [
-       "WebCryptoAPI/generateKey/successes_Ed448.https.any.worker.html",
+       "WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -472232,10 +472385,10 @@
        }
       ]
      ],
-     "successes_X448.https.any.js": [
+     "successes_X448.tentative.https.any.js": [
       "e7dbe32696d8fe4dc47445f6f0fa10f756f958aa",
       [
-       "WebCryptoAPI/generateKey/successes_X448.https.any.html",
+       "WebCryptoAPI/generateKey/successes_X448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -472263,7 +472416,7 @@
        }
       ],
       [
-       "WebCryptoAPI/generateKey/successes_X448.https.any.worker.html",
+       "WebCryptoAPI/generateKey/successes_X448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -472648,10 +472801,10 @@
        }
       ]
      ],
-     "okp_importKey_Ed448.https.any.js": [
+     "okp_importKey_Ed448.tentative.https.any.js": [
       "5bb7460c1fbc9333435925790cf8eacad7648611",
       [
-       "WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.html",
+       "WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -472679,7 +472832,7 @@
        }
       ],
       [
-       "WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.worker.html",
+       "WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -472766,10 +472919,10 @@
        }
       ]
      ],
-     "okp_importKey_X448.https.any.js": [
+     "okp_importKey_X448.tentative.https.any.js": [
       "f8552be3c826dcf1f3511a5ad8cba295c62c1923",
       [
-       "WebCryptoAPI/import_export/okp_importKey_X448.https.any.html",
+       "WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -472797,7 +472950,7 @@
        }
       ],
       [
-       "WebCryptoAPI/import_export/okp_importKey_X448.https.any.worker.html",
+       "WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -472884,10 +473037,10 @@
        }
       ]
      ],
-     "okp_importKey_failures_Ed448.https.any.js": [
+     "okp_importKey_failures_Ed448.tentative.https.any.js": [
       "8ff3de5c79d3ab8f59f17051d5560b3e61371b11",
       [
-       "WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.html",
+       "WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -472915,7 +473068,7 @@
        }
       ],
       [
-       "WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker.html",
+       "WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -473002,10 +473155,10 @@
        }
       ]
      ],
-     "okp_importKey_failures_X448.https.any.js": [
+     "okp_importKey_failures_X448.tentative.https.any.js": [
       "eccce68fac731cd751f7b8819fe24401055fe3a9",
       [
-       "WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.html",
+       "WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -473033,7 +473186,7 @@
        }
       ],
       [
-       "WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker.html",
+       "WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -473271,10 +473424,10 @@
        }
       ]
      ],
-     "eddsa_curve448.https.any.js": [
+     "eddsa_curve448.tentative.https.any.js": [
       "6960c296bae6afd67878cbac0bec69dc7de77c71",
       [
-       "WebCryptoAPI/sign_verify/eddsa_curve448.https.any.html",
+       "WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.html",
        {
         "script_metadata": [
          [
@@ -473298,7 +473451,7 @@
        }
       ],
       [
-       "WebCryptoAPI/sign_verify/eddsa_curve448.https.any.worker.html",
+       "WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.worker.html",
        {
         "script_metadata": [
          [
@@ -506579,7 +506732,7 @@
        ]
       ],
       "CSS-supports-CSSStyleDeclaration.html": [
-       "daec039e406d51bfe67587ed096a74d20bbeeee7",
+       "c1ab19daec2ab3b6dd64c1a551283fee3e58175a",
        [
         null,
         {}
@@ -511360,7 +511513,7 @@
      ],
      "variations": {
       "at-font-face-descriptors.html": [
-       "7e9792730dc1abf1cfa5b2e3c281ef9ea8794bc2",
+       "0787ec252cc89a9732370cfc27b40f6472404fbf",
        [
         null,
         {}
@@ -519384,6 +519537,15 @@
        {}
       ]
      ],
+     "scroll-marker-double-activation.html": [
+      "ee621980c286c4544f2f4c1c43eee38193c602e7",
+      [
+       null,
+       {
+        "testdriver": true
+       }
+      ]
+     ],
      "scroll-marker-elementFromPoint.html": [
       "cbe9bfc88711a9ed0e2149e1869194f7bfb4b366",
       [
@@ -522948,7 +523110,7 @@
        ]
       ],
       "mouse-wheel.html": [
-       "287e594cab4be93210f13042c32300f83d5f7278",
+       "b55d5484b37673088d6748e74d013f2bdabd96ad",
        [
         null,
         {
@@ -531008,6 +531170,15 @@
        {}
       ]
      ],
+     "hittest-preserve-3d.html": [
+      "6d4138e473f3393fe109301a7c63411baf812876",
+      [
+       null,
+       {
+        "testdriver": true
+       }
+      ]
+     ],
      "inheritance.html": [
       "2d7b0940846331812bd0eecb22513a76b9ce7d27",
       [
@@ -536122,7 +536293,7 @@
       ]
      ],
      "getComputedStyle-calc-mixed-units-003.html": [
-      "7fa4eeee642b25fe762ba9650e22dfd86c232dbd",
+      "aaa84ec8f715e9df078bbffd83ac6d144135433d",
       [
        null,
        {}
@@ -544230,6 +544401,15 @@
       {}
      ]
     ],
+    "behaves-like-button.tentative.html": [
+     "719ce316681d4bef8e6fd33c4fa2b7620db5c5eb",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "builtin-coverage.html": [
      "e3001a2c4855e9c10afaf46cdd2fe60fcd2a1cd3",
      [
@@ -550054,7 +550234,7 @@
        ]
       ],
       "css-transition-cross-document.html": [
-       "de30e9e9db9ce992c7fb0ed61d0001ad1aa34de7",
+       "b165d8298ab1962aa3ea0a326794427a0a3bc1aa",
        [
         null,
         {}
@@ -550119,7 +550299,7 @@
        ]
       ],
       "iframe-document-preserve.window.js": [
-       "4f9fa7540f69067549872615d92a05ed783f18f3",
+       "9edc44a31690c1d278c9395b3e5aba82ba9f36a7",
        [
         "dom/nodes/moveBefore/iframe-document-preserve.window.html",
         {
@@ -550153,6 +550333,13 @@
         {}
        ]
       ],
+      "moveBefore-from-light-to-shadow.html": [
+       "d0ca56887012bdc4ef39d5c3bea6665a2b5cf41b",
+       [
+        null,
+        {}
+       ]
+      ],
       "moveBefore-shadow-inside.html": [
        "239b08ee95b76d9626001756c59cf9ac9e9da634",
        [
@@ -550244,7 +550431,7 @@
        ]
       ],
       "selection-preserve.html": [
-       "cb49e19d72978e4ec7e97a7077f96b36779191e0",
+       "25ff3d24f15dfcc39a56915776211d212a015b55",
        [
         null,
         {
@@ -572013,6 +572200,15 @@
       }
      ]
     ],
+    "fedcm-accounts-endpoint-rejects-redirects.https.html": [
+     "ae3b52a5789ec96193a35b62c60fc8ee67bf13b4",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "fedcm-accounts-push": {
      "fedcm-accounts-push-basic.tentative.https.html": [
       "3affa4e3a6d745c8e5f0802e287cc3d16ee89ee1",
@@ -572271,8 +572467,8 @@
       }
      ]
     ],
-    "fedcm-domainhint.https.html": [
-     "20b4569a05e67d47a2aba9913bd330ceef98aef4",
+    "fedcm-domainhint-any.https.html": [
+     "80952ac169c0c4d0068b8a51558af3c38514bd45",
      [
       null,
       {
@@ -572280,8 +572476,17 @@
       }
      ]
     ],
-    "fedcm-endpoint-redirects.https.html": [
-     "71dbce03267e86e00fd90e1b69abf186b0fdd3a3",
+    "fedcm-domainhint-matches-account.https.html": [
+     "6285647ace69b48255e4e193468256e6458a1d3f",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "fedcm-domainhint-matches-from-two-accounts.https.html": [
+     "195337318fbf33a0d4b935871ef70de610fdbba9",
      [
       null,
       {
@@ -572455,6 +572660,15 @@
       ]
      ]
     },
+    "fedcm-no-domainhint-matches-account.https.html": [
+     "c2bf1419022277649c6ba7861bc366f4ac438778",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "fedcm-no-login-url.https.html": [
      "94592d2dbfbfb9f308f4aa97a198816119a36502",
      [
@@ -572574,6 +572788,15 @@
       }
      ]
     ],
+    "fedcm-token-endpoint-rejects-redirects.https.html": [
+     "8d74e06bb2203e98fc5ec01af070e1087cf48615",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "fedcm-token-returned-with-http-error.https.html": [
      "7c7687f00f344dd42639a8be3590545a93adf882",
      [
@@ -644553,6 +644776,13 @@
          {}
         ]
        ],
+       "patching-pseudo.html": [
+        "7724d2e1f260b2d9c8976a5beccd8952dd829c89",
+        [
+         null,
+         {}
+        ]
+       ],
        "template-patchfor-innerHTML-ambiguous.html": [
         "f83395850de49835ddfda11449ebf52c9a49d9fa",
         [
@@ -656420,8 +656650,35 @@
          }
         ]
        ],
+       "radio-focus-navigation-checked.html": [
+        "623182498ff0e63e4b0b3b5583c188f43fee362c",
+        [
+         null,
+         {
+          "testdriver": true
+         }
+        ]
+       ],
        "radio-focus-navigation-disabled.html": [
-        "1aaedf8bb1a438f4ed97d614a7b3649df45694c7",
+        "b35a6b8d6e5b089349678605b51841962fb18051",
+        [
+         null,
+         {
+          "testdriver": true
+         }
+        ]
+       ],
+       "radio-focus-navigation-group-first-focus.html": [
+        "73ca65489b2d57f89513c03be57436aab40517ac",
+        [
+         null,
+         {
+          "testdriver": true
+         }
+        ]
+       ],
+       "radio-focus-navigation-group-focusable-focus.html": [
+        "7885332cc4b8dbfd55d730c23f14504cb6d29e11",
         [
          null,
          {
@@ -686636,14 +686893,15 @@
      ]
     ],
     "RelativeOrientationSensor-iframe-access.https.html": [
-     "7e55cb3b69e7bbe5d82b95ff7d557ce329e0a7bf",
+     "10fcb50c3b6731fb63429a846e6111b944264511",
      [
       null,
       {
        "testdriver": true,
        "testdriver_features": [
         "bidi"
-       ]
+       ],
+       "timeout": "long"
       }
      ]
     ],
@@ -721178,6 +721436,15 @@
         {}
        ]
       ],
+      "task-attribution-link-load.html": [
+       "6518df1beaa8f7401fbc4313971075606e14400b",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
       "task-attribution.html": [
        "0c27fbb06058b3fb949e609dee9ea857a9682d27",
        [
@@ -762576,7 +762843,7 @@
        ]
       ],
       "k-rate-connections.html": [
-       "730f03e5619577abf98c30b5566cddeeccf31551",
+       "6a46da41d3d22de51f1bb962ff7fcdc452a82eab",
        [
         null,
         {}
@@ -773569,6 +773836,13 @@
        {}
       ]
      ],
+     "setter-argument.html": [
+      "bfa4291b236533b2d35796872632d2b7579be766",
+      [
+       null,
+       {}
+      ]
+     ],
      "window-named-properties-object.html": [
       "cc4976890683f444cdd29b9fce591207b0def240",
       [
@@ -776379,7 +776653,7 @@
       ]
      ],
      "clamp.https.any.js": [
-      "b3ccdcddca306b018f64011210da3036ee66cf6f",
+      "ebcec4233963c3c8ea23adfc6703856a589d2b30",
       [
        "webnn/conformance_tests/clamp.https.any.html?cpu",
        {
@@ -782354,6 +782628,117 @@
        }
       ]
      ],
+     "mlNumber.https.any.js": [
+      "643d09b767c8528e921bd714a1beabeaf4beeb83",
+      [
+       "webnn/conformance_tests/mlNumber.https.any.html?cpu",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "test WebNN MLNumber"
+         ],
+         [
+          "global",
+          "window"
+         ],
+         [
+          "variant",
+          "?cpu"
+         ],
+         [
+          "variant",
+          "?gpu"
+         ],
+         [
+          "variant",
+          "?npu"
+         ],
+         [
+          "script",
+          "../resources/utils.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "webnn/conformance_tests/mlNumber.https.any.html?gpu",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "test WebNN MLNumber"
+         ],
+         [
+          "global",
+          "window"
+         ],
+         [
+          "variant",
+          "?cpu"
+         ],
+         [
+          "variant",
+          "?gpu"
+         ],
+         [
+          "variant",
+          "?npu"
+         ],
+         [
+          "script",
+          "../resources/utils.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ],
+      [
+       "webnn/conformance_tests/mlNumber.https.any.html?npu",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "test WebNN MLNumber"
+         ],
+         [
+          "global",
+          "window"
+         ],
+         [
+          "variant",
+          "?cpu"
+         ],
+         [
+          "variant",
+          "?gpu"
+         ],
+         [
+          "variant",
+          "?npu"
+         ],
+         [
+          "script",
+          "../resources/utils.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ],
      "mul.https.any.js": [
       "f8606849dd42aa96f5a8c5bf3a28ba05d3634956",
       [
@@ -790179,7 +790564,7 @@
       ]
      ],
      "clamp.https.any.js": [
-      "3d2d5d7d0fd1f98177b176a52dd8f3f274091b12",
+      "933d86adf74765d43ba0c4c27396b62f03b0a401",
       [
        "webnn/validation_tests/clamp.https.any.html?cpu",
        {
@@ -804855,6 +805240,15 @@
       }
      ]
     ],
+    "RTCDataChannel-worker-GC.html": [
+     "dffc170f1bd1d7073a4ac9b474ea48266931810e",
+     [
+      null,
+      {
+       "timeout": "long"
+      }
+     ]
+    ],
     "RTCDataChannelEvent-constructor.html": [
      "265943ae56350e01d14cd4d1cfdd7c86635e49b5",
      [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/blob-valid-after-abort.any.js b/third_party/blink/web_tests/external/wpt/IndexedDB/blob-valid-after-abort.any.js
new file mode 100644
index 0000000..169073b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/blob-valid-after-abort.any.js
@@ -0,0 +1,33 @@
+// META: title=Blob Valid After Abort
+// META: global=window,worker
+// META: script=resources/support.js
+
+let key = "key";
+
+indexeddb_test(
+  function upgrade(t, db) {
+    db.createObjectStore('store');
+    },
+    function success(t, db) {
+      const blobAContent = 'Blob A content';
+      const blobA = new Blob([blobAContent], { 'type': 'text/plain' });
+      const value = { a0: blobA };
+
+      const txn = db.transaction('store', 'readwrite');
+      const store = txn.objectStore('store');
+
+      store.put(value, key);
+      const request = store.get(key);
+      request.onsuccess = t.step_func(function () {
+        readBlob = request.result.a0;
+        txn.abort();
+      });
+
+      let readBlob;
+      txn.onabort = () => {
+        readBlob.text().then(
+          t.step_func_done(text => assert_equals(text, blobAContent)),
+          t.unreached_func());
+      };
+    },
+  "A blob can be read back after the transaction that added it was aborted.");
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_bits_curve448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/derive_bits_keys/cfrg_curves_keys_curve448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_Ed448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures_X448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_Ed448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/successes_X448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_Ed448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_X448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.https.any-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.https.any.js
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.worker-expected.txt
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.https.any.worker-expected.txt
rename to third_party/blink/web_tests/external/wpt/WebCryptoAPI/sign_verify/eddsa_curve448.tentative.https.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js b/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js
index f680cd8b..42369c7 100644
--- a/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js
+++ b/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js
@@ -20,6 +20,7 @@
   var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST);
   var OTHER_HOST = '{{domains[www2]}}';
   var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('{{hosts[alt][]}}');
+  var OTHER_NOTSAMESITE_HOST = '{{hosts[alt][www2]}}';
 
   return {
     HTTP_PORT: HTTP_PORT,
@@ -45,6 +46,7 @@
     HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
     HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
     HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
+    HTTPS_OTHER_NOTSAMESITE_ORIGIN: 'https://' + OTHER_NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
     UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
     AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
   };
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-display-none-crash.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-display-none-crash.html
index bf513e3..4c02cd6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-display-none-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-display-none-crash.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
 <link rel="help" href="https://issues.chromium.org/issues/406054648">
-<html class="reftest-wait">
+<html class="test-wait">
   <style>
     @position-try --pf {
       position-anchor: --b;
@@ -14,7 +14,7 @@
     requestAnimationFrame(()=> {
       requestAnimationFrame(()=> {
         elm.style.display = "none";
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/uncontained-oof-in-inline-after-break-000-crash.html b/third_party/blink/web_tests/external/wpt/css/css-break/uncontained-oof-in-inline-after-break-000-crash.html
index 4d301e4..262c8b9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-break/uncontained-oof-in-inline-after-break-000-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/uncontained-oof-in-inline-after-break-000-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1285743">
   <div style="columns:2; line-height:20px;">
@@ -18,7 +18,7 @@
       requestAnimationFrame(()=> {
         b.style.columns = "2";
         c.style.columns = "3";
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-layout-root-crash.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-layout-root-crash.html
index e3e709a2..55702868 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-layout-root-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/chrome-layout-root-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <link rel="help" href="https://crbug.com/1371820">
 <style>
   body, div, img { container-type: size; }
@@ -12,6 +12,6 @@
     img.alt = img.src = "b";
     // Marks div size container for layout which skips style recalc for the sub-tree.
     div.style.width = "500px";
-    document.documentElement.classList.remove("reftest-wait");
+    document.documentElement.classList.remove("test-wait");
   }));
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/size-change-during-transition-crash.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/size-change-during-transition-crash.html
index 80be45b..3546ce44 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/size-change-during-transition-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/container-queries/crashtests/size-change-during-transition-crash.html
@@ -1,8 +1,7 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <meta charset="utf-8">
 <title>Container Queries - Size change during transitions crash</title>
-<script src="/common/reftest-wait.js"></script>
 <link rel="help" href="https://crbug.com/1451359">
 <style>
   #outer {
@@ -32,7 +31,7 @@
   requestAnimationFrame(() => {
     requestAnimationFrame(() => {
       outer.style.width = "300px";
-      takeScreenshot();
+      document.documentElement.removeAttribute("class");
     });
   });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-CSSStyleDeclaration.html b/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-CSSStyleDeclaration.html
index daec039..c1ab19d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-CSSStyleDeclaration.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-conditional/js/CSS-supports-CSSStyleDeclaration.html
@@ -34,7 +34,9 @@
   "-moz-animation-name",
   "-moz-animation-play-state",
   "-moz-animation-timing-function",
-  "-moz-appearance",
+  // -moz-appearance may be disabled from CSSStyleProperties.
+  // See also https://bugzilla.mozilla.org/show_bug.cgi?id=1977489
+  // "-moz-appearance",
   "-moz-backface-visibility",
   "-moz-binding",
   "-moz-border-bottom-colors",
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/detach-locked-slot-children-crash.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/detach-locked-slot-children-crash.html
index 409a9697..9b6ee9c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/detach-locked-slot-children-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/detach-locked-slot-children-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <link rel="help" href="https://crbug.com/1284278">
 <body dir="auto">
   <p>Pass if no crash.</p>
@@ -13,6 +13,6 @@
     marquee.appendChild(details.firstChild);
     img.srcset = "dummy";
     img.alt = "dummy";
-    document.documentElement.classList.remove("reftest-wait");
+    document.documentElement.classList.remove("test-wait");
   }));
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html
index 920305c..5a7a41b94 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/touch-action-beside-display-locked-fixedpos-iframe-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1434550">
   <button id="boo"></button>
@@ -10,7 +10,7 @@
     requestAnimationFrame(()=> {
       requestAnimationFrame(()=> {
         boo.style.touchAction = "pan-x";
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended-ref.html
new file mode 100644
index 0000000..e7dc0f5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended-ref.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div>&#x58f1;&#x842c;</div>
+<div>&#x5f10;&#x842c;</div>
+<div>&#x4f0d;&#x842c;</div>
+<div>&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x58f1;&#x842c;&#x5f10;&#x9621;&#x53c2;&#x767e;&#x56db;&#x62fe;&#x4f0d;</div>
+<div>&#x58f1;&#x842c;&#x58f1;</div>
+<div>&#x58f1;&#x842c;&#x58f1;&#x62fe;</div>
+<div>&#x58f1;&#x842c;&#x58f1;&#x767e;</div>
+<div>&#x58f1;&#x842c;&#x58f1;&#x9621;</div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div>&#x58f1;&#x5104;</div>
+<div>&#x5f10;&#x5104;</div>
+<div>&#x4f0d;&#x5104;</div>
+<div>&#x4e5d;&#x5104;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x58f1;&#x5104;&#x5f10;&#x9621;&#x53c2;&#x767e;&#x56db;&#x62fe;&#x4f0d;&#x842c;&#x516d;&#x9621;&#x4e03;&#x767e;&#x516b;&#x62fe;&#x4e5d;</div>
+<div>&#x58f1;&#x5104;&#x58f1;</div>
+<div>&#x58f1;&#x5104;&#x58f1;&#x842c;</div>
+<div>&#x58f1;&#x5104;&#x58f1;&#x62fe;&#x842c;</div>
+<div>&#x58f1;&#x5104;&#x58f1;&#x62fe;&#x842c;</div>
+<div>&#x58f1;&#x5104;&#x58f1;&#x9621;&#x842c;</div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div>&#x58f1;&#x5146;</div>
+<div>&#x5f10;&#x5146;</div>
+<div>&#x4f0d;&#x5146;</div>
+<div>&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5146;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5104;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x58f1;&#x62fe;&#x5146;</div>
+<div>&#x4f0d;&#x62fe;&#x5146;</div>
+<div>&#x4e5d;&#x62fe;&#x4e5d;&#x5146;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5104;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x58f1;&#x767e;&#x5146;</div>
+<div>&#x4f0d;&#x767e;&#x5146;</div>
+<div>&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5146;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5104;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x58f1;&#x9621;&#x5f10;&#x767e;&#x53c2;&#x62fe;&#x56db;&#x5146;&#x4f0d;&#x767e;&#x516d;&#x62fe;&#x4e03;&#x5104;&#x516b;&#x9621;&#x4e5d;&#x842c;&#x58f1;&#x767e;&#x5f10;&#x62fe;&#x53c2;</div>
+<div>&#x58f1;&#x5146;&#x58f1;</div>
+<div>&#x58f1;&#x5146;&#x58f1;&#x842c;</div>
+<div>&#x58f1;&#x5146;&#x58f1;&#x5104;</div>
+<div>&#x58f1;&#x5146;&#x58f1;&#x767e;&#x5104;</div>
+<div>&#x58f1;&#x5146;&#x58f1;&#x62fe;&#x5104;</div>
+<div>&#x58f1;&#x5146;&#x58f1;&#x9621;&#x5104;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x58f1;&#x9621;&#x58f1;&#x5146;&#x58f1;&#x9621;&#x58f1;&#x5104;&#x58f1;&#x9621;&#x58f1;&#x842c;&#x58f1;&#x9621;&#x58f1;</div>
+<div>&#x58f1;&#x9621;&#x58f1;&#x62fe;&#x5146;&#x58f1;&#x767e;&#x58f1;&#x62fe;&#x5104;&#x58f1;&#x9621;&#x58f1;&#x62fe;&#x842c;&#x58f1;&#x767e;&#x58f1;</div>
+<div>&#x58f1;&#x9621;&#x58f1;&#x767e;&#x58f1;&#x842c;&#x58f1;</div>
+<div>&#x4f0d;&#x9621;&#x4f0d;&#x5146;&#x4f0d;&#x9621;&#x4f0d;&#x5104;&#x4f0d;&#x9621;&#x4f0d;&#x842c;&#x4f0d;&#x9621;&#x4f0d;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x58f1;&#x5146;</div>
+<div>&#x58f1;&#x5104;</div>
+<div>&#x58f1;&#x767e;&#x842c;</div>
+<div>&#x58f1;&#x9621;</div>
+<div>&#x58f1;&#x62fe;&#x5146;</div>
+<div>&#x58f1;&#x767e;&#x5146;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5146;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5104;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+<div>&#x58f1;&#x9621;&#x5146;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x58f1;&#x842c;</div>
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x58f1;&#x5104;</div>
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x58f1;&#x5146;</div>
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5146;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x5104;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;&#x842c;&#x4e5d;&#x9621;&#x4e5d;&#x767e;&#x4e5d;&#x62fe;&#x4e5d;</div>
+
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x58f1;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended.html
new file mode 100644
index 0000000..62357c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-extended.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Extended Implementation (optional)</title>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#extended-range-optional">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
+<link rel="match" href="counter-japanese-formal-extended-ref.html">
+<style>
+  div::after {
+    content: counter(n, japanese-formal);
+  }
+</style>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
+<div style="counter-reset: n 10001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
+
+<div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-ref.html
index 67482303..d7a8474 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal-ref.html
@@ -13,24 +13,11 @@
 <div>&#x58f1;&#x62fe;</div>
 <div>&#x58f1;&#x767e;</div>
 <div>&#x58f1;&#x9621;</div>
-<div>&#x58f1;&#x842c;</div>
-<div>&#x58f1;&#x62fe;&#x842c;</div>
-<div>&#x58f1;&#x767e;&#x842c;</div>
-<div>&#x58f1;&#x9621;&#x842c;</div>
-<div>&#x58f1;&#x5104;</div>
-<div>&#x58f1;&#x62fe;&#x5104;</div>
 
 <div>&#x58f1;&#x62fe;&#x58f1;</div>
 <div>&#x4e5d;&#x62fe;&#x4e5d;</div>
 <div>&#x58f1;&#x767e;&#x58f1;</div>
 <div>&#x5f10;&#x767e;</div>
 <div>&#x516d;&#x9621;&#x58f1;</div>
-<div>&#x58f1;&#x842c;&#x58f1;</div>
-<div>&#x58f1;&#x842c;&#x58f1;&#x62fe;&#x58f1;</div>
-<div>&#x58f1;&#x842c;&#x58f1;&#x767e;&#x58f1;</div>
-<div>&#x58f1;&#x842c;&#x58f1;&#x9621;&#x58f1;&#x767e;&#x58f1;&#x62fe;&#x58f1;</div>
-<div>&#x58f1;&#x9621;&#x58f1;&#x767e;&#x842c;</div>
-<div>&#x58f1;&#x5104;&#x58f1;&#x842c;&#x58f1;</div>
-<div>&#x58f1;&#x5104;&#x58f1;&#x62fe;&#x58f1;&#x842c;&#x58f1;</div>
 
 <div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x58f1;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal.html
index 6558514..c67ce6c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-formal/counter-japanese-formal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Japanese Limited-range Implementation (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-japanese">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-japanese-formal-ref.html">
 <style>
   div::after {
@@ -20,24 +22,11 @@
 <div style="counter-reset: n 10;"></div>
 <div style="counter-reset: n 100;"></div>
 <div style="counter-reset: n 1000;"></div>
-<div style="counter-reset: n 10000;"></div>
-<div style="counter-reset: n 100000;"></div>
-<div style="counter-reset: n 1000000;"></div>
-<div style="counter-reset: n 10000000;"></div>
-<div style="counter-reset: n 100000000;"></div>
-<div style="counter-reset: n 1000000000;"></div>
 
 <div style="counter-reset: n 11;"></div>
 <div style="counter-reset: n 99;"></div>
 <div style="counter-reset: n 101;"></div>
 <div style="counter-reset: n 200;"></div>
 <div style="counter-reset: n 6001;"></div>
-<div style="counter-reset: n 10001;"></div>
-<div style="counter-reset: n 10011;"></div>
-<div style="counter-reset: n 10101;"></div>
-<div style="counter-reset: n 11111;"></div>
-<div style="counter-reset: n 11000000;"></div>
-<div style="counter-reset: n 100010001;"></div>
-<div style="counter-reset: n 100110001;"></div>
 
 <div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended-ref.html
new file mode 100644
index 0000000..5957cd2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended-ref.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (万) - ten-thousands group -->
+<div>&#x4e00;&#x4e07;</div>
+<div>&#x4e8c;&#x4e07;</div>
+<div>&#x4e94;&#x4e07;</div>
+<div>&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x4e00;&#x4e07;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;</div>
+<div>&#x4e00;&#x4e07;&#x4e00;</div>
+<div>&#x4e00;&#x4e07;&#x5341;</div>
+<div>&#x4e00;&#x4e07;&#x4e00;&#x767e;</div>
+<div>&#x4e00;&#x4e07;&#x4e00;&#x5343;</div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div>&#x4e00;&#x5104;</div>
+<div>&#x4e8c;&#x5104;</div>
+<div>&#x4e94;&#x5104;</div>
+<div>&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x4e00;&#x5104;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x4e07;&#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x5104;&#x4e00;</div>
+<div>&#x4e00;&#x5104;&#x4e00;&#x4e07;</div>
+<div>&#x4e00;&#x5104;&#x5341;&#x4e07;</div>
+<div>&#x4e00;&#x5104;&#x5341;&#x4e07;</div>
+<div>&#x4e00;&#x5104;&#x4e00;&#x5343;&#x4e07;</div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div>&#x4e00;&#x5146;</div>
+<div>&#x4e8c;&#x5146;</div>
+<div>&#x4e94;&#x5146;</div>
+<div>&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x4e00;&#x5341;&#x5146;</div>
+<div>&#x4e94;&#x5341;&#x5146;</div>
+<div>&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x4e00;&#x767e;&#x5146;</div>
+<div>&#x4e94;&#x767e;&#x5146;</div>
+<div>&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x4e00;&#x5343;&#x4e8c;&#x767e;&#x4e09;&#x5341;&#x56db;&#x5146;&#x4e94;&#x767e;&#x516d;&#x5341;&#x4e03;&#x5104;&#x516b;&#x5343;&#x4e5d;&#x4e07;&#x4e00;&#x767e;&#x4e8c;&#x5341;&#x4e09;</div>
+<div>&#x4e00;&#x5146;&#x4e00;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x4e07;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x5104;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x767e;&#x5104;</div>
+<div>&#x4e00;&#x5146;&#x5341;&#x5104;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x5343;&#x5104;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x4e00;&#x5343;&#x4e00;&#x5146;&#x4e00;&#x5343;&#x4e00;&#x5104;&#x4e00;&#x5343;&#x4e00;&#x4e07;&#x4e00;&#x5343;&#x4e00;</div>
+<div>&#x4e00;&#x5343;&#x5341;&#x5146;&#x4e00;&#x767e;&#x5341;&#x5104;&#x4e00;&#x5343;&#x5341;&#x4e07;&#x4e00;&#x767e;&#x4e00;</div>
+<div>&#x4e00;&#x5343;&#x767e;&#x4e07;&#x4e00;</div>
+<div>&#x4e94;&#x5343;&#x4e94;&#x5146;&#x4e94;&#x5343;&#x4e94;&#x5104;&#x4e94;&#x5343;&#x4e94;&#x4e07;&#x4e94;&#x5343;&#x4e94;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x4e00;&#x5146;</div>
+<div>&#x4e00;&#x5104;</div>
+<div>&#x4e00;&#x767e;&#x4e07;</div>
+<div>&#x4e00;&#x5343;</div>
+<div>&#x5341;&#x5146;</div>
+<div>&#x4e00;&#x767e;&#x5146;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x5343;&#x5146;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e00;&#x4e07;</div>
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e00;&#x5104;</div>
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e00;&#x5146;</div>
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e00;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended.html
new file mode 100644
index 0000000..8a72eaa6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-extended.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Extended Implementation (optional)</title>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#extended-range-optional">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
+<link rel="match" href="counter-japanese-informal-extended-ref.html">
+<style>
+  div::after {
+    content: counter(n, japanese-informal);
+  }
+</style>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (万) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
+<div style="counter-reset: n 10001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
+
+<div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-ref.html
index a08a636..f5e9376 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal-ref.html
@@ -13,24 +13,11 @@
 <div>&#x5341;</div>
 <div>&#x767e;</div>
 <div>&#x5343;</div>
-<div>&#x4e00;&#x4e07;</div>
-<div>&#x5341;&#x4e07;</div>
-<div>&#x767e;&#x4e07;</div>
-<div>&#x4e00;&#x5343;&#x4e07;</div>
-<div>&#x4e00;&#x5104;</div>
-<div>&#x5341;&#x5104;</div>
 
 <div>&#x5341;&#x4e00;</div>
 <div>&#x4e5d;&#x5341;&#x4e5d;</div>
 <div>&#x767e;&#x4e00;</div>
 <div>&#x4e8c;&#x767e;</div>
 <div>&#x516d;&#x5343;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x5341;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x767e;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x4e00;&#x5343;&#x767e;&#x5341;&#x4e00;</div>
-<div>&#x4e00;&#x5343;&#x767e;&#x4e07;</div>
-<div>&#x4e00;&#x5104;&#x4e00;&#x4e07;&#x4e00;</div>
-<div>&#x4e00;&#x5104;&#x5341;&#x4e00;&#x4e07;&#x4e00;</div>
 
 <div>&#x30de;&#x30a4;&#x30ca;&#x30b9;&#x4e00;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal.html
index 5263e99..4493545 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/japanese-informal/counter-japanese-informal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Japanese Limited-range Implementation (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-japanese">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-japanese-informal-ref.html">
 <style>
   div::after {
@@ -20,24 +22,11 @@
 <div style="counter-reset: n 10;"></div>
 <div style="counter-reset: n 100;"></div>
 <div style="counter-reset: n 1000;"></div>
-<div style="counter-reset: n 10000;"></div>
-<div style="counter-reset: n 100000;"></div>
-<div style="counter-reset: n 1000000;"></div>
-<div style="counter-reset: n 10000000;"></div>
-<div style="counter-reset: n 100000000;"></div>
-<div style="counter-reset: n 1000000000;"></div>
 
 <div style="counter-reset: n 11;"></div>
 <div style="counter-reset: n 99;"></div>
 <div style="counter-reset: n 101;"></div>
 <div style="counter-reset: n 200;"></div>
 <div style="counter-reset: n 6001;"></div>
-<div style="counter-reset: n 10001;"></div>
-<div style="counter-reset: n 10011;"></div>
-<div style="counter-reset: n 10101;"></div>
-<div style="counter-reset: n 11111;"></div>
-<div style="counter-reset: n 11000000;"></div>
-<div style="counter-reset: n 100010001;"></div>
-<div style="counter-reset: n 100110001;"></div>
 
 <div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended-ref.html
new file mode 100644
index 0000000..3adaa81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended-ref.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-korean">
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (만) - ten-thousands group -->
+<div>&#xc77c;&#xb9cc;</div>
+<div>&#xc774;&#xb9cc;</div>
+<div>&#xc624;&#xb9cc;</div>
+<div>&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#xc77c;&#xb9cc; &#xc774;&#xcc9c;&#xc0bc;&#xbc31;&#xc0ac;&#xc2ed;&#xc624;</div>
+<div>&#xc77c;&#xb9cc; &#xc77c;</div>
+<div>&#xc77c;&#xb9cc; &#xc2ed;</div>
+<div>&#xc77c;&#xb9cc; &#xbc31;</div>
+<div>&#xc77c;&#xb9cc; &#xcc9c;</div>
+
+<!-- Test third group marker (억) - hundred-millions group -->
+<div>&#xc77c;&#xc5b5;</div>
+<div>&#xc774;&#xc5b5;</div>
+<div>&#xc624;&#xc5b5;</div>
+<div>&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#xc77c;&#xc5b5; &#xc774;&#xcc9c;&#xc0bc;&#xbc31;&#xc0ac;&#xc2ed;&#xc624;&#xb9cc; &#xc721;&#xcc9c;&#xce60;&#xbc31;&#xd314;&#xc2ed;&#xad6c;</div>
+<div>&#xc77c;&#xc5b5; &#xc77c;</div>
+<div>&#xc77c;&#xc5b5; &#xc77c;&#xb9cc;</div>
+<div>&#xc77c;&#xc5b5; &#xc2ed;&#xb9cc;</div>
+<div>&#xc77c;&#xc5b5; &#xbc31;&#xb9cc;</div>
+<div>&#xc77c;&#xc5b5; &#xcc9c;&#xb9cc;</div>
+
+<!-- Test fourth group marker (조) - trillions group -->
+<div>&#xc77c;&#xc870;</div>
+<div>&#xc774;&#xc870;</div>
+<div>&#xc624;&#xc870;</div>
+<div>&#xad6c;&#xc870; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#xc2ed;&#xc870;</div>
+<div>&#xc624;&#xc2ed;&#xc870;</div>
+<div>&#xad6c;&#xc2ed;&#xad6c;&#xc870; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#xbc31;&#xc870;</div>
+<div>&#xc624;&#xbc31;&#xc870;</div>
+<div>&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc870; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#xc77c;&#xc870; &#xc774;&#xcc9c;&#xc0bc;&#xbc31;&#xc0ac;&#xc2ed;&#xc624;&#xc5b5; &#xc721;&#xcc9c;&#xce60;&#xbc31;&#xd314;&#xc2ed;&#xad6c;&#xb9cc; &#xbc31;&#xc774;&#xc2ed;&#xc0bc;</div>
+<div>&#xc77c;&#xc870; &#xc77c;</div>
+<div>&#xc77c;&#xc870; &#xc77c;&#xb9cc;</div>
+<div>&#xc77c;&#xc870; &#xbc31;&#xb9cc;</div>
+<div>&#xc77c;&#xc870; &#xcc9c;&#xb9cc;</div>
+<div>&#xc77c;&#xc870; &#xcc9c;&#xc5b5;</div>
+<div>&#xc77c;&#xc870; &#xcc9c;&#xc77c;&#xc5b5;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#xc77c;&#xc870; &#xcc9c;&#xc77c;&#xc5b5; &#xbc31;&#xc77c;&#xb9cc; &#xcc9c;&#xc77c;</div>
+<div>&#xc77c;&#xc870; &#xcc9c;&#xc2ed;&#xc5b5; &#xcc9c;&#xc2ed;&#xb9cc; &#xcc9c;&#xc2ed;&#xc77c;</div>
+<div>&#xc77c;&#xc870; &#xcc9c;&#xc5b5; &#xc2ed;&#xb9cc; &#xc77c;</div>
+<div>&#xc624;&#xc870; &#xc624;&#xcc9c;&#xc624;&#xc5b5; &#xc624;&#xbc31;&#xc624;&#xb9cc; &#xc624;&#xcc9c;&#xc624;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#xc77c;&#xc870;</div>
+<div>&#xc2ed;&#xc5b5;</div>
+<div>&#xbc31;&#xb9cc;</div>
+<div>&#xcc9c;</div>
+<div>&#xc2ed;&#xc870;</div>
+<div>&#xbc31;&#xc870;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc870; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+<div>&#xcc9c;&#xc870;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;&#xb9cc;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;&#xc5b5;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;&#xc870;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc870; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended.html
new file mode 100644
index 0000000..9dbbc6c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-extended.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Extended Implementation (optional)</title>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#extended-range-optional">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
+<link rel="match" href="counter-korean-hangul-formal-extended-ref.html">
+<style>
+  div::after {
+    content: counter(n, korean-hangul-formal);
+  }
+</style>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (만) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
+<div style="counter-reset: n 10001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (억) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (조) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
+
+<div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-ref.html
index 641fa5d..8beab9a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal-ref.html
@@ -13,24 +13,11 @@
 <div>&#xc77c;&#xc2ed;,</div>
 <div>&#xc77c;&#xbc31;,</div>
 <div>&#xc77c;&#xcc9c;,</div>
-<div>&#xc77c;&#xb9cc;,</div>
-<div>&#xc77c;&#xc2ed;&#xb9cc;,</div>
-<div>&#xc77c;&#xbc31;&#xb9cc;,</div>
-<div>&#xc77c;&#xcc9c;&#xb9cc;,</div>
-<div>&#xc77c;&#xc5b5;,</div>
-<div>&#xc77c;&#xc2ed;&#xc5b5;,</div>
 
 <div>&#xc77c;&#xc2ed;&#xc77c;,</div>
 <div>&#xad6c;&#xc2ed;&#xad6c;,</div>
 <div>&#xc77c;&#xbc31;&#xc77c;,</div>
 <div>&#xc774;&#xbc31;,</div>
 <div>&#xc721;&#xcc9c;&#xc77c;,</div>
-<div>&#xc77c;&#xb9cc; &#xc77c;,</div>
-<div>&#xc77c;&#xb9cc; &#xc77c;&#xc2ed;&#xc77c;,</div>
-<div>&#xc77c;&#xb9cc; &#xc77c;&#xbc31;&#xc77c;,</div>
-<div>&#xc77c;&#xb9cc; &#xc77c;&#xcc9c;&#xc77c;&#xbc31;&#xc77c;&#xc2ed;&#xc77c;,</div>
-<div>&#xc77c;&#xcc9c;&#xc77c;&#xbc31;&#xb9cc;,</div>
-<div>&#xc77c;&#xc5b5; &#xc77c;&#xb9cc; &#xc77c;,</div>
-<div>&#xc77c;&#xc5b5; &#xc77c;&#xc2ed;&#xc77c;&#xb9cc; &#xc77c;,</div>
 
 <div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;,</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal.html
index 468e0b87..cff3e72 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hangul-formal/counter-korean-hangul-formal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Korean Limited-range Implementation (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-korean">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-korean-hangul-formal-ref.html">
 <style>
   div::before {
@@ -20,24 +22,11 @@
 <div style="counter-reset: n 10;">,</div>
 <div style="counter-reset: n 100;">,</div>
 <div style="counter-reset: n 1000;">,</div>
-<div style="counter-reset: n 10000;">,</div>
-<div style="counter-reset: n 100000;">,</div>
-<div style="counter-reset: n 1000000;">,</div>
-<div style="counter-reset: n 10000000;">,</div>
-<div style="counter-reset: n 100000000;">,</div>
-<div style="counter-reset: n 1000000000;">,</div>
 
 <div style="counter-reset: n 11;">,</div>
 <div style="counter-reset: n 99;">,</div>
 <div style="counter-reset: n 101;">,</div>
 <div style="counter-reset: n 200;">,</div>
 <div style="counter-reset: n 6001;">,</div>
-<div style="counter-reset: n 10001;">,</div>
-<div style="counter-reset: n 10011;">,</div>
-<div style="counter-reset: n 10101;">,</div>
-<div style="counter-reset: n 11111;">,</div>
-<div style="counter-reset: n 11000000;">,</div>
-<div style="counter-reset: n 100010001;">,</div>
-<div style="counter-reset: n 100110001;">,</div>
 
 <div style="counter-reset: n -1;">,</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended-ref.html
new file mode 100644
index 0000000..a5b55cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended-ref.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-korean">
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div>&#x58f9;&#x842c;</div>
+<div>&#x8cb3;&#x842c;</div>
+<div>&#x4f0d;&#x842c;</div>
+<div>&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x58f9;&#x842c; &#x8cb3;&#x4edf;&#x53c3;&#x4f70;&#x8086;&#x62fe;&#x4f0d;</div>
+<div>&#x58f9;&#x842c; &#x58f9;</div>
+<div>&#x58f9;&#x842c; &#x62fe;</div>
+<div>&#x58f9;&#x842c; &#x58f9;&#x4f70;</div>
+<div>&#x58f9;&#x842c; &#x58f9;&#x4edf;</div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div>&#x58f9;&#x5104;</div>
+<div>&#x8cb3;&#x5104;</div>
+<div>&#x4f0d;&#x5104;</div>
+<div>&#x7396;&#x5104; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x58f9;&#x5104; &#x8cb3;&#x4edf;&#x53c3;&#x4f70;&#x8086;&#x62fe;&#x4f0d;&#x842c; &#x9678;&#x4edf;&#x67d2;&#x4f70;&#x634c;&#x62fe;&#x7396;</div>
+<div>&#x58f9;&#x5104; &#x58f9;</div>
+<div>&#x58f9;&#x5104; &#x58f9;&#x842c;</div>
+<div>&#x58f9;&#x5104; &#x62fe;&#x842c;</div>
+<div>&#x58f9;&#x5104; &#x58f9;&#x4f70;&#x842c;</div>
+<div>&#x58f9;&#x5104; &#x58f9;&#x4edf;&#x842c;</div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div>&#x58f9;&#x5146;</div>
+<div>&#x8cb3;&#x5146;</div>
+<div>&#x4f0d;&#x5146;</div>
+<div>&#x7396;&#x5146; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x62fe;&#x5146;</div>
+<div>&#x4f0d;&#x62fe;&#x5146;</div>
+<div>&#x7396;&#x62fe;&#x7396;&#x5146; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x58f9;&#x4f70;&#x5146;</div>
+<div>&#x4f0d;&#x4f70;&#x5146;</div>
+<div>&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5146; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x58f9;&#x5146; &#x8cb3;&#x4edf;&#x53c3;&#x4f70;&#x8086;&#x62fe;&#x4f0d;&#x5104; &#x9678;&#x4edf;&#x67d2;&#x4f70;&#x634c;&#x62fe;&#x7396;&#x842c; &#x58f9;&#x4f70;&#x8cb3;&#x62fe;&#x53c3;</div>
+<div>&#x58f9;&#x5146; &#x58f9;</div>
+<div>&#x58f9;&#x5146; &#x58f9;&#x842c;</div>
+<div>&#x58f9;&#x5146; &#x58f9;&#x4f70;&#x842c;</div>
+<div>&#x58f9;&#x5146; &#x58f9;&#x4edf;&#x842c;</div>
+<div>&#x58f9;&#x5146; &#x58f9;&#x4edf;&#x5104;</div>
+<div>&#x58f9;&#x5146; &#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x5104;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x58f9;&#x5146; &#x58f9;&#x4edf;&#x58f9;&#x5104; &#x58f9;&#x4edf;&#x58f9;&#x842c; &#x58f9;&#x4edf;&#x58f9;</div>
+<div>&#x58f9;&#x5146; &#x62fe;&#x5104; &#x62fe;&#x842c; &#x62fe;&#x58f9;</div>
+<div>&#x58f9;&#x5146; &#x58f9;&#x4f70;&#x5104; &#x62fe;&#x842c; &#x58f9;</div>
+<div>&#x4f0d;&#x5146; &#x4f0d;&#x4edf;&#x4f0d;&#x5104; &#x4f0d;&#x4f70;&#x4f0d;&#x842c; &#x4f0d;&#x4edf;&#x4f0d;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x58f9;&#x5146;</div>
+<div>&#x62fe;&#x5104;</div>
+<div>&#x58f9;&#x4f70;&#x842c;</div>
+<div>&#x58f9;&#x4edf;</div>
+<div>&#x62fe;&#x5146;</div>
+<div>&#x58f9;&#x4f70;&#x5146;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5146; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+<div>&#x58f9;&#x4edf;&#x5146;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x58f9;&#x842c;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x58f9;&#x5104;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x58f9;&#x5146;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5146; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c; &#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x58f9;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended.html
new file mode 100644
index 0000000..e7d4e1f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-extended.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Extended Implementation (optional)</title>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#extended-range-optional">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
+<link rel="match" href="counter-korean-hanja-formal-extended-ref.html">
+<style>
+  div::after {
+    content: counter(n, korean-hanja-formal);
+  }
+</style>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
+<div style="counter-reset: n 10001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
+
+<div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-ref.html
index da1f8a48..ba4e39d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal-ref.html
@@ -13,24 +13,11 @@
 <div>&#x58f9;&#x62fe;,</div>
 <div>&#x58f9;&#x767e;,</div>
 <div>&#x58f9;&#x4edf;,</div>
-<div>&#x58f9;&#x842c;,</div>
-<div>&#x58f9;&#x62fe;&#x842c;,</div>
-<div>&#x58f9;&#x767e;&#x842c;,</div>
-<div>&#x58f9;&#x4edf;&#x842c;,</div>
-<div>&#x58f9;&#x5104;,</div>
-<div>&#x58f9;&#x62fe;&#x5104;,</div>
 
 <div>&#x58f9;&#x62fe;&#x58f9;,</div>
 <div>&#x4e5d;&#x62fe;&#x4e5d;,</div>
 <div>&#x58f9;&#x767e;&#x58f9;,</div>
 <div>&#x8cb3;&#x767e;,</div>
 <div>&#x516d;&#x4edf;&#x58f9;,</div>
-<div>&#x58f9;&#x842c; &#x58f9;,</div>
-<div>&#x58f9;&#x842c; &#x58f9;&#x62fe;&#x58f9;,</div>
-<div>&#x58f9;&#x842c; &#x58f9;&#x767e;&#x58f9;,</div>
-<div>&#x58f9;&#x842c; &#x58f9;&#x4edf;&#x58f9;&#x767e;&#x58f9;&#x62fe;&#x58f9;,</div>
-<div>&#x58f9;&#x4edf;&#x58f9;&#x767e;&#x842c;,</div>
-<div>&#x58f9;&#x5104; &#x58f9;&#x842c; &#x58f9;,</div>
-<div>&#x58f9;&#x5104; &#x58f9;&#x62fe;&#x58f9;&#x842c; &#x58f9;,</div>
 
 <div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x58f9;,</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal.html
index c6fb66a7..6aa0023 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-formal/counter-korean-hanja-formal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Korean Limited-range Implementation (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-korean">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-korean-hanja-formal-ref.html">
 <style>
   div::before {
@@ -20,24 +22,11 @@
 <div style="counter-reset: n 10;">,</div>
 <div style="counter-reset: n 100;">,</div>
 <div style="counter-reset: n 1000;">,</div>
-<div style="counter-reset: n 10000;">,</div>
-<div style="counter-reset: n 100000;">,</div>
-<div style="counter-reset: n 1000000;">,</div>
-<div style="counter-reset: n 10000000;">,</div>
-<div style="counter-reset: n 100000000;">,</div>
-<div style="counter-reset: n 1000000000;">,</div>
 
 <div style="counter-reset: n 11;">,</div>
 <div style="counter-reset: n 99;">,</div>
 <div style="counter-reset: n 101;">,</div>
 <div style="counter-reset: n 200;">,</div>
 <div style="counter-reset: n 6001;">,</div>
-<div style="counter-reset: n 10001;">,</div>
-<div style="counter-reset: n 10011;">,</div>
-<div style="counter-reset: n 10101;">,</div>
-<div style="counter-reset: n 11111;">,</div>
-<div style="counter-reset: n 11000000;">,</div>
-<div style="counter-reset: n 100010001;">,</div>
-<div style="counter-reset: n 100110001;">,</div>
 
 <div style="counter-reset: n -1;">,</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended-ref.html
new file mode 100644
index 0000000..18e6114d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended-ref.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-korean">
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (万) - ten-thousands group -->
+<div>&#x4e00;&#x4e07;</div>
+<div>&#x4e8c;&#x4e07;</div>
+<div>&#x4e94;&#x4e07;</div>
+<div>&#x4e5d;&#x4e07; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x4e00;&#x4e07; &#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;</div>
+<div>&#x4e00;&#x4e07; &#x4e00;</div>
+<div>&#x4e00;&#x4e07; &#x5341;</div>
+<div>&#x4e00;&#x4e07; &#x767e;</div>
+<div>&#x4e00;&#x4e07; &#x4e00;&#x5343;</div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div>&#x4e00;&#x5104;</div>
+<div>&#x4e8c;&#x5104;</div>
+<div>&#x4e94;&#x5104;</div>
+<div>&#x4e5d;&#x5104; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x4e00;&#x5104; &#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x4e07; &#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x5104; &#x4e00;</div>
+<div>&#x4e00;&#x5104; &#x4e00;&#x4e07;</div>
+<div>&#x4e00;&#x5104; &#x5341;&#x4e07;</div>
+<div>&#x4e00;&#x5104; &#x767e;&#x4e07;</div>
+<div>&#x4e00;&#x5104; &#x4e00;&#x5343;&#x4e07;</div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div>&#x4e00;&#x5146;</div>
+<div>&#x4e8c;&#x5146;</div>
+<div>&#x4e94;&#x5146;</div>
+<div>&#x4e5d;&#x5146; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x5341;&#x5146;</div>
+<div>&#x4e94;&#x5341;&#x5146;</div>
+<div>&#x4e5d;&#x5341;&#x4e5d;&#x5146; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x767e;&#x5146;</div>
+<div>&#x4e94;&#x767e;&#x5146;</div>
+<div>&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x4e00;&#x5146; &#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x5104; &#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;&#x4e07; &#x767e;&#x4e8c;&#x5341;&#x4e09;</div>
+<div>&#x4e00;&#x5146; &#x4e00;</div>
+<div>&#x4e00;&#x5146; &#x4e00;&#x4e07;</div>
+<div>&#x4e00;&#x5146; &#x767e;&#x4e07;</div>
+<div>&#x4e00;&#x5146; &#x4e00;&#x5343;&#x4e07;</div>
+<div>&#x4e00;&#x5146; &#x4e00;&#x5343;&#x5104;</div>
+<div>&#x4e00;&#x5146; &#x4e00;&#x5343;&#x4e00;&#x767e;&#x5104;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x4e00;&#x5146; &#x4e00;&#x5343;&#x4e00;&#x5104; &#x4e00;&#x5343;&#x4e00;&#x4e07; &#x4e00;&#x5343;&#x4e00;</div>
+<div>&#x4e00;&#x5146; &#x5341;&#x5104; &#x5341;&#x4e07; &#x5341;&#x4e00;</div>
+<div>&#x4e00;&#x5146; &#x767e;&#x5104; &#x5341;&#x4e07; &#x4e00;</div>
+<div>&#x4e94;&#x5146; &#x4e94;&#x5343;&#x4e94;&#x5104; &#x4e94;&#x767e;&#x4e94;&#x4e07; &#x4e94;&#x5343;&#x4e94;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x4e00;&#x5146;</div>
+<div>&#x5341;&#x5104;</div>
+<div>&#x767e;&#x4e07;</div>
+<div>&#x5343;</div>
+<div>&#x5341;&#x5146;</div>
+<div>&#x767e;&#x5146;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07; &#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+<div>&#x5343;&#x5146;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;&#xb9cc;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;&#xc5b5;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;&#xc870;</div>
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc870; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xc5b5; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;&#xb9cc; &#xad6c;&#xcc9c;&#xad6c;&#xbc31;&#xad6c;&#xc2ed;&#xad6c;</div>
+
+<div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#xc77c;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended.html
new file mode 100644
index 0000000..d575047
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-extended.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Extended Implementation (optional)</title>
+<link rel="help" href="https://drafts.csswg.org/css-counter-styles/#extended-range-optional">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
+<link rel="match" href="counter-korean-hanja-informal-extended-ref.html">
+<style>
+  div::after {
+    content: counter(n, korean-hanja-informal);
+  }
+</style>
+
+<!-- Extended range implementation tests (algorithm step 2: split into 4-digit groups) -->
+<!-- Test second group marker (万) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
+<div style="counter-reset: n 10001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
+
+<div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-ref.html
index 1a7286f..5ddae77 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal-ref.html
@@ -13,24 +13,11 @@
 <div>&#x5341;,</div>
 <div>&#x767e;,</div>
 <div>&#x5343;,</div>
-<div>&#x842c;,</div>
-<div>&#x5341;&#x842c;,</div>
-<div>&#x767e;&#x842c;,</div>
-<div>&#x5343;&#x842c;,</div>
-<div>&#x4e00;&#x5104;,</div>
-<div>&#x5341;&#x5104;,</div>
 
 <div>&#x5341;&#x4e00;,</div>
 <div>&#x4e5d;&#x5341;&#x4e5d;,</div>
 <div>&#x767e;&#x4e00;,</div>
 <div>&#x4e8c;&#x767e;,</div>
 <div>&#x516d;&#x5343;&#x4e00;,</div>
-<div>&#x842c; &#x4e00;,</div>
-<div>&#x842c; &#x5341;&#x4e00;,</div>
-<div>&#x842c; &#x767e;&#x4e00;,</div>
-<div>&#x842c; &#x5343;&#x767e;&#x5341;&#x4e00;,</div>
-<div>&#x5343;&#x767e;&#x842c;,</div>
-<div>&#x4e00;&#x5104; &#x842c; &#x4e00;,</div>
-<div>&#x4e00;&#x5104; &#x5341;&#x4e00;&#x842c; &#x4e00;,</div>
 
 <div>&#xb9c8;&#xc774;&#xb108;&#xc2a4; &#x4e00;,</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal.html
index dc16c88..e967dae 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/korean-hanja-informal/counter-korean-hanja-informal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Korean Limited-range Implementation (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-korean">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-korean-hanja-informal-ref.html">
 <style>
   div::before {
@@ -20,24 +22,11 @@
 <div style="counter-reset: n 10;">,</div>
 <div style="counter-reset: n 100;">,</div>
 <div style="counter-reset: n 1000;">,</div>
-<div style="counter-reset: n 10000;">,</div>
-<div style="counter-reset: n 100000;">,</div>
-<div style="counter-reset: n 1000000;">,</div>
-<div style="counter-reset: n 10000000;">,</div>
-<div style="counter-reset: n 100000000;">,</div>
-<div style="counter-reset: n 1000000000;">,</div>
 
 <div style="counter-reset: n 11;">,</div>
 <div style="counter-reset: n 99;">,</div>
 <div style="counter-reset: n 101;">,</div>
 <div style="counter-reset: n 200;">,</div>
 <div style="counter-reset: n 6001;">,</div>
-<div style="counter-reset: n 10001;">,</div>
-<div style="counter-reset: n 10011;">,</div>
-<div style="counter-reset: n 10101;">,</div>
-<div style="counter-reset: n 11111;">,</div>
-<div style="counter-reset: n 11000000;">,</div>
-<div style="counter-reset: n 100010001;">,</div>
-<div style="counter-reset: n 100110001;">,</div>
 
 <div style="counter-reset: n -1;">,</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal-ref.html
index 9a39f67..4a3b7f25 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal-ref.html
@@ -13,24 +13,91 @@
 <div>&#x58f9;&#x62fe;</div>
 <div>&#x58f9;&#x4f70;</div>
 <div>&#x58f9;&#x4edf;</div>
-<div>&#x58f9;&#x4e07;</div>
-<div>&#x58f9;&#x62fe;&#x4e07;</div>
-<div>&#x58f9;&#x4f70;&#x4e07;</div>
-<div>&#x58f9;&#x4edf;&#x4e07;</div>
-<div>&#x58f9;&#x4ebf;</div>
-<div>&#x58f9;&#x62fe;&#x4ebf;</div>
 
 <div>&#x58f9;&#x62fe;&#x58f9;</div>
 <div>&#x7396;&#x62fe;&#x7396;</div>
 <div>&#x58f9;&#x4f70;&#x96f6;&#x58f9;</div>
 <div>&#x8d30;&#x4f70;</div>
 <div>&#x9646;&#x4edf;&#x96f6;&#x58f9;</div>
+
+<!-- Test second group marker (万) - ten-thousands group -->
+<div>&#x58f9;&#x4e07;</div>
+<div>&#x8d30;&#x4e07;</div>
+<div>&#x4f0d;&#x4e07;</div>
+<div>&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x58f9;&#x4e07;&#x8d30;&#x4edf;&#x53c1;&#x4f70;&#x8086;&#x62fe;&#x4f0d;</div>
 <div>&#x58f9;&#x4e07;&#x96f6;&#x58f9;</div>
-<div>&#x58f9;&#x4e07;&#x96f6;&#x58f9;&#x62fe;&#x58f9;</div>
-<div>&#x58f9;&#x4e07;&#x96f6;&#x58f9;&#x4f70;&#x96f6;&#x58f9;</div>
-<div>&#x58f9;&#x4e07;&#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x58f9;&#x62fe;&#x58f9;</div>
-<div>&#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x4e07;</div>
-<div>&#x58f9;&#x4ebf;&#x96f6;&#x58f9;&#x4e07;&#x96f6;&#x58f9;</div>
-<div>&#x58f9;&#x4ebf;&#x96f6;&#x58f9;&#x62fe;&#x58f9;&#x4e07;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x4e07;&#x96f6;&#x62fe;</div>
+<div>&#x58f9;&#x4e07;&#x96f6;&#x58f9;&#x4f70;</div>
+<div>&#x58f9;&#x4e07;&#x58f9;&#x4edf;</div>
+
+<!-- Test third group marker (亿) - hundred-millions group -->
+<div>&#x58f9;&#x4ebf;</div>
+<div>&#x8d30;&#x4ebf;</div>
+<div>&#x4f0d;&#x4ebf;</div>
+<div>&#x7396;&#x4ebf;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x58f9;&#x4ebf;&#x8d30;&#x4edf;&#x53c1;&#x4f70;&#x8086;&#x62fe;&#x4f0d;&#x4e07;&#x9646;&#x4edf;&#x67d2;&#x4f70;&#x634c;&#x62fe;&#x7396;</div>
+<div>&#x58f9;&#x4ebf;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x4ebf;&#x96f6;&#x58f9;&#x4e07;</div>
+<div>&#x58f9;&#x4ebf;&#x96f6;&#x62fe;&#x4e07;</div>
+<div>&#x58f9;&#x4ebf;&#x96f6;&#x58f9;&#x4f70;&#x4e07;</div>
+<div>&#x58f9;&#x4ebf;&#x58f9;&#x4edf;&#x4e07;</div>
+
+<!-- Test fourth group marker (万亿) - trillions group -->
+<div>&#x58f9;&#x4e07;&#x4ebf;</div>
+<div>&#x8d30;&#x4e07;&#x4ebf;</div>
+<div>&#x4f0d;&#x4e07;&#x4ebf;</div>
+<div>&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x4ebf;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x62fe;&#x4e07;&#x4ebf;</div>
+<div>&#x4f0d;&#x62fe;&#x4e07;&#x4ebf;</div>
+<div>&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x4ebf;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x58f9;&#x4f70;&#x4e07;&#x4ebf;</div>
+<div>&#x4f0d;&#x4f70;&#x4e07;&#x4ebf;</div>
+<div>&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x4ebf;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x58f9;&#x4e07;&#x8d30;&#x4edf;&#x53c1;&#x4f70;&#x8086;&#x62fe;&#x4f0d;&#x4e07;&#x4ebf;&#x9646;&#x4edf;&#x67d2;&#x4f70;&#x634c;&#x62fe;&#x7396;&#x4e07;&#x96f6;&#x58f9;&#x4f70;&#x8d30;&#x62fe;&#x53c1;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x96f6;&#x58f9;&#x4e07;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x96f6;&#x58f9;&#x4f70;&#x4e07;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x96f6;&#x58f9;&#x4edf;&#x4e07;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x58f9;&#x4edf;&#x4ebf;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x4ebf;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x58f9;&#x4e07;&#x96f6;&#x58f9;&#x4e07;&#x4ebf;&#x58f9;&#x4edf;&#x96f6;&#x58f9;&#x4e07;&#x58f9;&#x4edf;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x4e07;&#x96f6;&#x62fe;&#x4e07;&#x4ebf;&#x58f9;&#x4edf;&#x96f6;&#x62fe;&#x4e07;&#x58f9;&#x4edf;&#x96f6;&#x62fe;&#x58f9;</div>
+<div>&#x58f9;&#x4e07;&#x4ebf;&#x58f9;&#x4edf;&#x4ebf;&#x96f6;&#x62fe;&#x4e07;&#x96f6;&#x58f9;</div>
+<div>&#x4f0d;&#x4e07;&#x96f6;&#x4f0d;&#x4e07;&#x4ebf;&#x4f0d;&#x4edf;&#x96f6;&#x4f0d;&#x4e07;&#x4f0d;&#x4edf;&#x96f6;&#x4f0d;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x58f9;&#x4e07;&#x4ebf;</div>
+<div>&#x62fe;&#x4ebf;</div>
+<div>&#x58f9;&#x4f70;&#x4e07;</div>
+<div>&#x58f9;&#x4edf;</div>
+<div>&#x62fe;&#x4e07;&#x4ebf;</div>
+<div>&#x58f9;&#x4f70;&#x4e07;&#x4ebf;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x4ebf;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+<div>&#x58f9;&#x4edf;&#x4e07;&#x4ebf;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#x8d1f;&#x58f9;&#x4e07;</div>
+<div>&#x8d1f;&#x58f9;&#x4ebf;</div>
+<div>&#x8d1f;&#x58f9;&#x4e07;&#x4ebf;</div>
+<div>&#x8d1f;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x4ebf;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x4e07;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
 
 <div>&#x8d1f;&#x58f9;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal.html
index 29bf952..2fced35 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-formal/counter-simp-chinese-formal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Chinese (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-chinese">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-simp-chinese-formal-ref.html">
 <style>
   div::after {
@@ -20,24 +22,91 @@
 <div style="counter-reset: n 10;"></div>
 <div style="counter-reset: n 100;"></div>
 <div style="counter-reset: n 1000;"></div>
-<div style="counter-reset: n 10000;"></div>
-<div style="counter-reset: n 100000;"></div>
-<div style="counter-reset: n 1000000;"></div>
-<div style="counter-reset: n 10000000;"></div>
-<div style="counter-reset: n 100000000;"></div>
-<div style="counter-reset: n 1000000000;"></div>
 
 <div style="counter-reset: n 11;"></div>
 <div style="counter-reset: n 99;"></div>
 <div style="counter-reset: n 101;"></div>
 <div style="counter-reset: n 200;"></div>
 <div style="counter-reset: n 6001;"></div>
+
+<!-- Test second group marker (万) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
 <div style="counter-reset: n 10001;"></div>
-<div style="counter-reset: n 10011;"></div>
-<div style="counter-reset: n 10101;"></div>
-<div style="counter-reset: n 11111;"></div>
-<div style="counter-reset: n 11000000;"></div>
-<div style="counter-reset: n 100010001;"></div>
-<div style="counter-reset: n 100110001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (亿) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (万亿) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
 
 <div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal-ref.html
index adc0a4c..e2272c69 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal-ref.html
@@ -13,24 +13,92 @@
 <div>&#x5341;</div>
 <div>&#x4e00;&#x767e;</div>
 <div>&#x4e00;&#x5343;</div>
-<div>&#x4e00;&#x4e07;</div>
-<div>&#x5341;&#x4e07;</div>
-<div>&#x4e00;&#x767e;&#x4e07;</div>
-<div>&#x4e00;&#x5343;&#x4e07;</div>
-<div>&#x4e00;&#x4ebf;</div>
-<div>&#x5341;&#x4ebf;</div>
 
 <div>&#x5341;&#x4e00;</div>
 <div>&#x4e5d;&#x5341;&#x4e5d;</div>
 <div>&#x4e00;&#x767e;&#x96f6;&#x4e00;</div>
 <div>&#x4e8c;&#x767e;</div>
 <div>&#x516d;&#x5343;&#x96f6;&#x4e00;</div>
+
+<!-- Test second group marker (万) - ten-thousands group -->
+<div>&#x4e00;&#x4e07;</div>
+<div>&#x4e8c;&#x4e07;</div>
+<div>&#x4e94;&#x4e07;</div>
+<div>&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x4e00;&#x4e07;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;</div>
 <div>&#x4e00;&#x4e07;&#x96f6;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x96f6;&#x4e00;&#x5341;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x96f6;&#x4e00;&#x767e;&#x96f6;&#x4e00;</div>
-<div>&#x4e00;&#x4e07;&#x4e00;&#x5343;&#x4e00;&#x767e;&#x4e00;&#x5341;&#x4e00;</div>
-<div>&#x4e00;&#x5343;&#x4e00;&#x767e;&#x4e07;</div>
-<div>&#x4e00;&#x4ebf;&#x96f6;&#x4e00;&#x4e07;&#x96f6;&#x4e00;</div>
-<div>&#x4e00;&#x4ebf;&#x96f6;&#x5341;&#x4e00;&#x4e07;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x4e07;&#x96f6;&#x5341;</div>
+<div>&#x4e00;&#x4e07;&#x96f6;&#x4e00;&#x767e;</div>
+<div>&#x4e00;&#x4e07;&#x4e00;&#x5343;</div>
+
+<!-- Test third group marker (亿) - hundred-millions group -->
+<div>&#x4e00;&#x4ebf;</div>
+<div>&#x4e8c;&#x4ebf;</div>
+<div>&#x4e94;&#x4ebf;</div>
+<div>&#x4e5d;&#x4ebf;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x4e00;&#x4ebf;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x4e07;&#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x4ebf;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x4ebf;&#x96f6;&#x4e00;&#x4e07;</div>
+<div>&#x4e00;&#x4ebf;&#x96f6;&#x5341;&#x4e07;</div>
+<div>&#x4e00;&#x4ebf;&#x96f6;&#x4e00;&#x767e;&#x4e07;</div>
+<div>&#x4e00;&#x4ebf;&#x4e00;&#x5343;&#x4e07;</div>
+
+<!-- Test fourth group marker (万亿) - trillions group -->
+<div>&#x4e00;&#x4e07;&#x4ebf;</div>
+<div>&#x4e8c;&#x4e07;&#x4ebf;</div>
+<div>&#x4e94;&#x4e07;&#x4ebf;</div>
+<div>&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4ebf;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x5341;&#x4e07;&#x4ebf;</div>
+<div>&#x4e94;&#x5341;&#x4e07;&#x4ebf;</div>
+<div>&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4ebf;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x4e00;&#x767e;&#x4e07;&#x4ebf;</div>
+<div>&#x4e94;&#x767e;&#x4e07;&#x4ebf;</div>
+<div>&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4ebf;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x4e00;&#x4e07;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x4e07;&#x4ebf;&#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;&#x4e07;&#x96f6;&#x4e00;&#x767e;&#x4e8c;&#x5341;&#x4e09;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x96f6;&#x4e00;&#x4e07;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x96f6;&#x4e00;&#x767e;&#x4e07;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x96f6;&#x4e00;&#x5343;&#x4e07;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x4e00;&#x5343;&#x4ebf;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x4e00;&#x5343;&#x4e00;&#x767e;&#x4ebf;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x4e00;&#x4e07;&#x96f6;&#x4e00;&#x4e07;&#x4ebf;&#x4e00;&#x5343;&#x96f6;&#x4e00;&#x4e07;&#x4e00;&#x5343;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x4e07;&#x96f6;&#x5341;&#x4e07;&#x4ebf;&#x4e00;&#x5343;&#x96f6;&#x5341;&#x4e07;&#x4e00;&#x5343;&#x96f6;&#x5341;&#x4e00;</div>
+<div>&#x4e00;&#x4e07;&#x4ebf;&#x4e00;&#x5343;&#x4ebf;&#x96f6;&#x5341;&#x4e07;&#x96f6;&#x4e00;</div>
+<div>&#x4e94;&#x4e07;&#x96f6;&#x4e94;&#x4e07;&#x4ebf;&#x4e94;&#x5343;&#x96f6;&#x4e94;&#x4e07;&#x4e94;&#x5343;&#x96f6;&#x4e94;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x4e00;&#x4e07;&#x4ebf;</div>
+<div>&#x5341;&#x4ebf;</div>
+<div>&#x4e00;&#x767e;&#x4e07;</div>
+<div>&#x4e00;&#x5343;</div>
+<div>&#x5341;&#x4e07;&#x4ebf;</div>
+<div>&#x4e00;&#x767e;&#x4e07;&#x4ebf;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4ebf;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x5343;&#x4e07;&#x4ebf;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#x8d1f;&#x4e00;&#x4e07;</div>
+<div>&#x8d1f;&#x4e00;&#x4ebf;</div>
+<div>&#x8d1f;&#x4e00;&#x4e07;&#x4ebf;</div>
+<div>&#x8d1f;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4ebf;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x4e07;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
 
 <div>&#x8d1f;&#x4e00;</div>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal.html
index 2cf29849..2293281 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/simp-chinese-informal/counter-simp-chinese-informal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Chinese (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-chinese">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-simp-chinese-informal-ref.html">
 <style>
   div::after {
@@ -20,24 +22,91 @@
 <div style="counter-reset: n 10;"></div>
 <div style="counter-reset: n 100;"></div>
 <div style="counter-reset: n 1000;"></div>
-<div style="counter-reset: n 10000;"></div>
-<div style="counter-reset: n 100000;"></div>
-<div style="counter-reset: n 1000000;"></div>
-<div style="counter-reset: n 10000000;"></div>
-<div style="counter-reset: n 100000000;"></div>
-<div style="counter-reset: n 1000000000;"></div>
 
 <div style="counter-reset: n 11;"></div>
 <div style="counter-reset: n 99;"></div>
 <div style="counter-reset: n 101;"></div>
 <div style="counter-reset: n 200;"></div>
 <div style="counter-reset: n 6001;"></div>
+
+<!-- Test second group marker (万) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
 <div style="counter-reset: n 10001;"></div>
-<div style="counter-reset: n 10011;"></div>
-<div style="counter-reset: n 10101;"></div>
-<div style="counter-reset: n 11111;"></div>
-<div style="counter-reset: n 11000000;"></div>
-<div style="counter-reset: n 100010001;"></div>
-<div style="counter-reset: n 100110001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (亿) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (万亿) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
 
 <div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal-ref.html
index 8437f83..d903809f6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal-ref.html
@@ -13,24 +13,92 @@
 <div>&#x58f9;&#x62fe;</div>
 <div>&#x58f9;&#x4f70;</div>
 <div>&#x58f9;&#x4edf;</div>
-<div>&#x58f9;&#x842c;</div>
-<div>&#x58f9;&#x62fe;&#x842c;</div>
-<div>&#x58f9;&#x4f70;&#x842c;</div>
-<div>&#x58f9;&#x4edf;&#x842c;</div>
-<div>&#x58f9;&#x5104;</div>
-<div>&#x58f9;&#x62fe;&#x5104;</div>
 
 <div>&#x58f9;&#x62fe;&#x58f9;</div>
 <div>&#x7396;&#x62fe;&#x7396;</div>
 <div>&#x58f9;&#x4f70;&#x96f6;&#x58f9;</div>
 <div>&#x8cb3;&#x4f70;</div>
 <div>&#x9678;&#x4edf;&#x96f6;&#x58f9;</div>
+
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div>&#x58f9;&#x842c;</div>
+<div>&#x8cb3;&#x842c;</div>
+<div>&#x4f0d;&#x842c;</div>
+<div>&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x58f9;&#x842c;&#x8cb3;&#x4edf;&#x53c3;&#x4f70;&#x8086;&#x62fe;&#x4f0d;</div>
 <div>&#x58f9;&#x842c;&#x96f6;&#x58f9;</div>
-<div>&#x58f9;&#x842c;&#x96f6;&#x58f9;&#x62fe;&#x58f9;</div>
-<div>&#x58f9;&#x842c;&#x96f6;&#x58f9;&#x4f70;&#x96f6;&#x58f9;</div>
-<div>&#x58f9;&#x842c;&#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x58f9;&#x62fe;&#x58f9;</div>
-<div>&#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x842c;</div>
-<div>&#x58f9;&#x5104;&#x96f6;&#x58f9;&#x842c;&#x96f6;&#x58f9;</div>
-<div>&#x58f9;&#x5104;&#x96f6;&#x58f9;&#x62fe;&#x58f9;&#x842c;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x842c;&#x96f6;&#x62fe;</div>
+<div>&#x58f9;&#x842c;&#x96f6;&#x58f9;&#x4f70;</div>
+<div>&#x58f9;&#x842c;&#x58f9;&#x4edf;</div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div>&#x58f9;&#x5104;</div>
+<div>&#x8cb3;&#x5104;</div>
+<div>&#x4f0d;&#x5104;</div>
+<div>&#x7396;&#x5104;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x58f9;&#x5104;&#x8cb3;&#x4edf;&#x53c3;&#x4f70;&#x8086;&#x62fe;&#x4f0d;&#x842c;&#x9678;&#x4edf;&#x67d2;&#x4f70;&#x634c;&#x62fe;&#x7396;</div>
+<div>&#x58f9;&#x5104;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x5104;&#x96f6;&#x58f9;&#x842c;</div>
+<div>&#x58f9;&#x5104;&#x96f6;&#x62fe;&#x842c;</div>
+<div>&#x58f9;&#x5104;&#x96f6;&#x58f9;&#x4f70;&#x842c;</div>
+<div>&#x58f9;&#x5104;&#x58f9;&#x4edf;&#x842c;</div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div>&#x58f9;&#x5146;</div>
+<div>&#x8cb3;&#x5146;</div>
+<div>&#x4f0d;&#x5146;</div>
+<div>&#x7396;&#x5146;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x62fe;&#x5146;</div>
+<div>&#x4f0d;&#x62fe;&#x5146;</div>
+<div>&#x7396;&#x62fe;&#x7396;&#x5146;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x58f9;&#x4f70;&#x5146;</div>
+<div>&#x4f0d;&#x4f70;&#x5146;</div>
+<div>&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5146;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x58f9;&#x5146;&#x8cb3;&#x4edf;&#x53c3;&#x4f70;&#x8086;&#x62fe;&#x4f0d;&#x5104;&#x9678;&#x4edf;&#x67d2;&#x4f70;&#x634c;&#x62fe;&#x7396;&#x842c;&#x96f6;&#x58f9;&#x4f70;&#x8cb3;&#x62fe;&#x53c3;</div>
+<div>&#x58f9;&#x5146;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x5146;&#x96f6;&#x58f9;&#x842c;</div>
+<div>&#x58f9;&#x5146;&#x96f6;&#x58f9;&#x4f70;&#x842c;</div>
+<div>&#x58f9;&#x5146;&#x96f6;&#x58f9;&#x4edf;&#x842c;</div>
+<div>&#x58f9;&#x5146;&#x58f9;&#x4edf;&#x5104;</div>
+<div>&#x58f9;&#x5146;&#x58f9;&#x4edf;&#x58f9;&#x4f70;&#x5104;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x58f9;&#x5146;&#x96f6;&#x58f9;&#x5104;&#x58f9;&#x4edf;&#x96f6;&#x58f9;&#x842c;&#x58f9;&#x4edf;&#x96f6;&#x58f9;</div>
+<div>&#x58f9;&#x5146;&#x96f6;&#x62fe;&#x5104;&#x58f9;&#x4edf;&#x96f6;&#x62fe;&#x842c;&#x58f9;&#x4edf;&#x96f6;&#x62fe;&#x58f9;</div>
+<div>&#x58f9;&#x5146;&#x58f9;&#x4edf;&#x5104;&#x96f6;&#x62fe;&#x842c;&#x96f6;&#x58f9;</div>
+<div>&#x4f0d;&#x5146;&#x96f6;&#x4f0d;&#x5104;&#x4f0d;&#x4edf;&#x96f6;&#x4f0d;&#x842c;&#x4f0d;&#x4edf;&#x96f6;&#x4f0d;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x58f9;&#x5146;</div>
+<div>&#x62fe;&#x5104;</div>
+<div>&#x58f9;&#x4f70;&#x842c;</div>
+<div>&#x58f9;&#x4edf;</div>
+<div>&#x62fe;&#x5146;</div>
+<div>&#x58f9;&#x4f70;&#x5146;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5146;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
+<div>&#x58f9;&#x4edf;&#x5146;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#x8ca0;&#x58f9;&#x842c;</div>
+<div>&#x8ca0;&#x58f9;&#x5104;</div>
+<div>&#x8ca0;&#x58f9;&#x5146;</div>
+<div>&#x8ca0;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5146;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x5104;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;&#x842c;&#x7396;&#x4edf;&#x7396;&#x4f70;&#x7396;&#x62fe;&#x7396;</div>
 
 <div>&#x8ca0;&#x58f9;</div>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal.html
index 4829d3d..2953afd 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-formal/counter-trad-chinese-formal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Chinese (required)</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-chinese">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-trad-chinese-formal-ref.html">
 <style>
   div::after {
@@ -20,24 +22,92 @@
 <div style="counter-reset: n 10;"></div>
 <div style="counter-reset: n 100;"></div>
 <div style="counter-reset: n 1000;"></div>
-<div style="counter-reset: n 10000;"></div>
-<div style="counter-reset: n 100000;"></div>
-<div style="counter-reset: n 1000000;"></div>
-<div style="counter-reset: n 10000000;"></div>
-<div style="counter-reset: n 100000000;"></div>
-<div style="counter-reset: n 1000000000;"></div>
 
 <div style="counter-reset: n 11;"></div>
 <div style="counter-reset: n 99;"></div>
 <div style="counter-reset: n 101;"></div>
 <div style="counter-reset: n 200;"></div>
 <div style="counter-reset: n 6001;"></div>
+
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
 <div style="counter-reset: n 10001;"></div>
-<div style="counter-reset: n 10011;"></div>
-<div style="counter-reset: n 10101;"></div>
-<div style="counter-reset: n 11111;"></div>
-<div style="counter-reset: n 11000000;"></div>
-<div style="counter-reset: n 100010001;"></div>
-<div style="counter-reset: n 100110001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
 
 <div style="counter-reset: n -1;"></div>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal-ref.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal-ref.html
index 2e156901..e8f11fc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal-ref.html
@@ -13,24 +13,91 @@
 <div>&#x5341;</div>
 <div>&#x4e00;&#x767e;</div>
 <div>&#x4e00;&#x5343;</div>
-<div>&#x4e00;&#x842c;<div>
-<div>&#x5341;&#x842c;</div>
-<div>&#x4e00;&#x767e;&#x842c;</div>
-<div>&#x4e00;&#x5343;&#x842c;</div>
-<div>&#x4e00;&#x5104;</div>
-<div>&#x5341;&#x5104;</div>
 
 <div>&#x5341;&#x4e00;</div>
 <div>&#x4e5d;&#x5341;&#x4e5d;</div>
 <div>&#x4e00;&#x767e;&#x96f6;&#x4e00;</div>
 <div>&#x4e8c;&#x767e;</div>
 <div>&#x516d;&#x5343;&#x96f6;&#x4e00;</div>
+
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div>&#x4e00;&#x842c;</div>
+<div>&#x4e8c;&#x842c;</div>
+<div>&#x4e94;&#x842c;</div>
+<div>&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div>&#x4e00;&#x842c;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;</div>
 <div>&#x4e00;&#x842c;&#x96f6;&#x4e00;</div>
-<div>&#x4e00;&#x842c;&#x96f6;&#x4e00;&#x5341;&#x4e00;</div>
-<div>&#x4e00;&#x842c;&#x96f6;&#x4e00;&#x767e;&#x96f6;&#x4e00;</div>
-<div>&#x4e00;&#x842c;&#x4e00;&#x5343;&#x4e00;&#x767e;&#x4e00;&#x5341;&#x4e00;</div>
-<div>&#x4e00;&#x5343;&#x4e00;&#x767e;&#x842c;</div>
-<div>&#x4e00;&#x5104;&#x96f6;&#x4e00;&#x842c;&#x96f6;&#x4e00;</div>
-<div>&#x4e00;&#x5104;&#x96f6;&#x5341;&#x4e00;&#x842c;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x842c;&#x96f6;&#x5341;</div>
+<div>&#x4e00;&#x842c;&#x96f6;&#x4e00;&#x767e;</div>
+<div>&#x4e00;&#x842c;&#x4e00;&#x5343;</div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div>&#x4e00;&#x5104;</div>
+<div>&#x4e8c;&#x5104;</div>
+<div>&#x4e94;&#x5104;</div>
+<div>&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div>&#x4e00;&#x5104;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x842c;&#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x5104;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x5104;&#x96f6;&#x4e00;&#x842c;</div>
+<div>&#x4e00;&#x5104;&#x96f6;&#x5341;&#x842c;</div>
+<div>&#x4e00;&#x5104;&#x96f6;&#x4e00;&#x767e;&#x842c;</div>
+<div>&#x4e00;&#x5104;&#x4e00;&#x5343;&#x842c;</div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div>&#x4e00;&#x5146;</div>
+<div>&#x4e8c;&#x5146;</div>
+<div>&#x4e94;&#x5146;</div>
+<div>&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div>&#x5341;&#x5146;</div>
+<div>&#x4e94;&#x5341;&#x5146;</div>
+<div>&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div>&#x4e00;&#x767e;&#x5146;</div>
+<div>&#x4e94;&#x767e;&#x5146;</div>
+<div>&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div>&#x4e00;&#x5146;&#x4e8c;&#x5343;&#x4e09;&#x767e;&#x56db;&#x5341;&#x4e94;&#x5104;&#x516d;&#x5343;&#x4e03;&#x767e;&#x516b;&#x5341;&#x4e5d;&#x842c;&#x96f6;&#x4e00;&#x767e;&#x4e8c;&#x5341;&#x4e09;</div>
+<div>&#x4e00;&#x5146;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x5146;&#x96f6;&#x4e00;&#x842c;</div>
+<div>&#x4e00;&#x5146;&#x96f6;&#x4e00;&#x767e;&#x842c;</div>
+<div>&#x4e00;&#x5146;&#x96f6;&#x4e00;&#x5343;&#x842c;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x5343;&#x5104;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x5343;&#x4e00;&#x767e;&#x5104;</div>
+
+<!-- Test interaction between multiple groups -->
+<div>&#x4e00;&#x5146;&#x96f6;&#x4e00;&#x5104;&#x4e00;&#x5343;&#x96f6;&#x4e00;&#x842c;&#x4e00;&#x5343;&#x96f6;&#x4e00;</div>
+<div>&#x4e00;&#x5146;&#x96f6;&#x5341;&#x5104;&#x4e00;&#x5343;&#x96f6;&#x5341;&#x842c;&#x4e00;&#x5343;&#x96f6;&#x5341;&#x4e00;</div>
+<div>&#x4e00;&#x5146;&#x4e00;&#x5343;&#x5104;&#x96f6;&#x5341;&#x842c;&#x96f6;&#x4e00;</div>
+<div>&#x4e94;&#x5146;&#x96f6;&#x4e94;&#x5104;&#x4e94;&#x5343;&#x96f6;&#x4e94;&#x842c;&#x4e94;&#x5343;&#x96f6;&#x4e94;</div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div>&#x4e00;&#x5146;</div>
+<div>&#x5341;&#x5104;</div>
+<div>&#x4e00;&#x767e;&#x842c;</div>
+<div>&#x4e00;&#x5343;</div>
+<div>&#x5341;&#x5146;</div>
+<div>&#x4e00;&#x767e;&#x5146;</div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div>&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
+<div>&#x4e00;&#x5343;&#x5146;</div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div>&#x4e00;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;&#x3007;</div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div>&#x8ca0;&#x4e00;&#x842c;</div>
+<div>&#x8ca0;&#x4e00;&#x5104;</div>
+<div>&#x8ca0;&#x4e00;&#x5146;</div>
+<div>&#x8ca0;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5146;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x5104;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;&#x842c;&#x4e5d;&#x5343;&#x4e5d;&#x767e;&#x4e5d;&#x5341;&#x4e5d;</div>
 
 <div>&#x8ca0;&#x4e00;</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal.html b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal.html
index 8fdc1c6c..a01074d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-counter-styles/trad-chinese-informal/counter-trad-chinese-informal.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
+<title>CSS Counter Styles: Longhand East Asian Counter Styles Trad Chinese Informal</title>
 <link rel="help" href="https://drafts.csswg.org/css-counter-styles/#limited-chinese">
+<link rel="author" href="mailto:saku@email.sakupi01.com" title="saku">
 <link rel="match" href="counter-trad-chinese-informal-ref.html">
 <style>
   div::after {
@@ -20,24 +22,91 @@
 <div style="counter-reset: n 10;"></div>
 <div style="counter-reset: n 100;"></div>
 <div style="counter-reset: n 1000;"></div>
-<div style="counter-reset: n 10000;"></div>
-<div style="counter-reset: n 100000;"></div>
-<div style="counter-reset: n 1000000;"></div>
-<div style="counter-reset: n 10000000;"></div>
-<div style="counter-reset: n 100000000;"></div>
-<div style="counter-reset: n 1000000000;"></div>
 
 <div style="counter-reset: n 11;"></div>
 <div style="counter-reset: n 99;"></div>
 <div style="counter-reset: n 101;"></div>
 <div style="counter-reset: n 200;"></div>
 <div style="counter-reset: n 6001;"></div>
+
+<!-- Test second group marker (萬) - ten-thousands group -->
+<div style="counter-reset: n 10000;"></div>
+<div style="counter-reset: n 20000;"></div>
+<div style="counter-reset: n 50000;"></div>
+<div style="counter-reset: n 99999;"></div>
+
+<!-- Test complex patterns within ten-thousands group (algorithm step 4: digit markers) -->
+<div style="counter-reset: n 12345;"></div>
 <div style="counter-reset: n 10001;"></div>
-<div style="counter-reset: n 10011;"></div>
-<div style="counter-reset: n 10101;"></div>
-<div style="counter-reset: n 11111;"></div>
-<div style="counter-reset: n 11000000;"></div>
-<div style="counter-reset: n 100010001;"></div>
-<div style="counter-reset: n 100110001;"></div>
+<div style="counter-reset: n 10010;"></div>
+<div style="counter-reset: n 10100;"></div>
+<div style="counter-reset: n 11000;"></div>
+
+<!-- Test third group marker (億) - hundred-millions group -->
+<div style="counter-reset: n 100000000;"></div>
+<div style="counter-reset: n 200000000;"></div>
+<div style="counter-reset: n 500000000;"></div>
+<div style="counter-reset: n 999999999;"></div>
+
+<!-- Test complex patterns within hundred-millions group (algorithm step 6: zero dropping) -->
+<div style="counter-reset: n 123456789;"></div>
+<div style="counter-reset: n 100000001;"></div>
+<div style="counter-reset: n 100010000;"></div>
+<div style="counter-reset: n 100100000;"></div>
+<div style="counter-reset: n 101000000;"></div>
+<div style="counter-reset: n 110000000;"></div>
+
+<!-- Test fourth group marker (兆) - trillions group -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 2000000000000;"></div>
+<div style="counter-reset: n 5000000000000;"></div>
+<div style="counter-reset: n 9999999999999;"></div>
+
+<!-- Test extended ranges (algorithm step 3: group markers up to 10^16) -->
+<!-- Test 10^13 range (ten-trillions) -->
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 50000000000000;"></div>
+<div style="counter-reset: n 99999999999999;"></div>
+
+<!-- Test 10^15 range (hundred-trillions) -->
+<div style="counter-reset: n 100000000000000;"></div>
+<div style="counter-reset: n 500000000000000;"></div>
+<div style="counter-reset: n 999999999999999;"></div>
+
+<!-- Test complex patterns in trillions group (step 5: drop ones, step 6: drop zeros) -->
+<div style="counter-reset: n 1234567890123;"></div>
+<div style="counter-reset: n 1000000000001;"></div>
+<div style="counter-reset: n 1000000010000;"></div>
+<div style="counter-reset: n 1000001000000;"></div>
+<div style="counter-reset: n 1000100000000;"></div>
+<div style="counter-reset: n 1010000000000;"></div>
+<div style="counter-reset: n 1100000000000;"></div>
+
+<!-- Test interaction between multiple groups -->
+<div style="counter-reset: n 1001001001001;"></div>
+<div style="counter-reset: n 1010101010101;"></div>
+<div style="counter-reset: n 1000100010001;"></div>
+<div style="counter-reset: n 5005005005005;"></div>
+
+<!-- Test zero dropping behavior across different groups -->
+<div style="counter-reset: n 1000000000000;"></div>
+<div style="counter-reset: n 1000000000;"></div>
+<div style="counter-reset: n 1000000;"></div>
+<div style="counter-reset: n 1000;"></div>
+<div style="counter-reset: n 10000000000000;"></div>
+<div style="counter-reset: n 100000000000000;"></div>
+
+<!-- Test boundary values at the edge of range (-10^16+1 to 10^16-1) -->
+<div style="counter-reset: n 9999999999999999;"></div>
+<div style="counter-reset: n 1000000000000000;"></div>
+
+<!-- Test out-of-range values (should fallback to cjk-decimal) -->
+<div style="counter-reset: n 10000000000000000;"></div>
+
+<!-- Test negative numbers (algorithm step 8: negative sign handling) -->
+<div style="counter-reset: n -10000;"></div>
+<div style="counter-reset: n -100000000;"></div>
+<div style="counter-reset: n -1000000000000;"></div>
+<div style="counter-reset: n -9999999999999999;"></div>
 
 <div style="counter-reset: n -1;"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-line-clamp-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-line-clamp-001-ref.html
index 9d03140f..c24d6197 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-line-clamp-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-line-clamp-001-ref.html
@@ -1,4 +1,5 @@
 <!DOCTYPE html>
+<meta charset="UTF-8">
 <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
 <style>
 .spacer {
@@ -9,22 +10,11 @@
   font: 50px/2 Ahem;
   height: 275px;
 }
-.clamp {
-  line-clamp: 3;
-}
-@supports not (line-clamp: 3) {
-  .clamp {
-    -webkit-line-clamp: 3;
-    display: -webkit-box;
-    -webkit-box-orient: vertical;
-    overflow: hidden;
-  }
-}
 </style>
 <div class="spacer"></div>
 <div class="target clamp">
   A<br>
   B<br>
-  C<br>
-  D</div>
+  C…
+</div>
 <div class="spacer"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-counter-crash.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-counter-crash.html
index fc8a38c62..27476ff 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-counter-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-counter-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <link rel="help" href="http://crbug.com/1487174">
 <style>
 * { counter-increment: c; }
@@ -7,7 +7,7 @@
 <script>
   function error_fn() {
     test.style.setProperty("text-orientation", "upright");
-    document.documentElement.classList.remove("reftest-wait");
+    document.documentElement.classList.remove("test-wait");
   }
 </script>
 <li id="test"></li>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-forward-finish.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-forward-finish.html
new file mode 100644
index 0000000..29108b1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-forward-finish.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#basic-shape-interpolation">
+<link rel="match" href="clip-path-animation-set-currenttime-ref.html">
+<style>
+  .container {
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    animation: clippath 10s;
+    animation-fill-mode: none;
+    clip-path: inset(33% 33%);
+  }
+
+  @keyframes clippath {
+    0% {
+      clip-path: circle(50% at 50% 50%);
+    }
+
+    100% {
+      clip-path: circle(35% at 35% 35%);
+    }
+  }
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/web-animations/resources/timing-utils.js"></script>
+
+<body>
+  <div class="container">
+  </div>
+
+  <script>
+    let animation = document.getAnimations()[0];
+    animation.ready.then(() => {
+      // Enough time to finish the animation
+      animation.currentTime = 10 * 1000 + 1;
+
+      // Since the animation is finished, and animation-fill-mode is none,
+      // we should get the original style set in css .container rather than
+      // any animated style.\
+      requestAnimationFrame(takeScreenshot);
+    });
+  </script>
+</body>
+
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-negative.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-negative.html
new file mode 100644
index 0000000..11ef17c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-negative.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#basic-shape-interpolation">
+<link rel="match" href="clip-path-animation-set-currenttime-ref.html">
+<style>
+  .container {
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    animation: clippath 10s;
+    animation-fill-mode: none;
+    clip-path: inset(33% 33%);
+  }
+
+  @keyframes clippath {
+    0% {
+      clip-path: circle(50% at 50% 50%);
+    }
+
+    100% {
+      clip-path: circle(35% at 35% 35%);
+    }
+  }
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/web-animations/resources/timing-utils.js"></script>
+
+<body>
+  <div class="container">
+  </div>
+
+  <script>
+    let animation = document.getAnimations()[0];
+    animation.ready.then(() => {
+      // With fill-mode: none, any negative time should return to the previous non-animated style.
+      animation.currentTime = -1000;
+      requestAnimationFrame(takeScreenshot);
+    });
+  </script>
+</body>
+
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-ref.html
new file mode 100644
index 0000000..b653929
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-currenttime-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>
+.container {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  clip-path: inset(33%);
+}
+</style>
+<body>
+<div class="container"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-duration-animation-finish.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-duration-animation-finish.html
new file mode 100644
index 0000000..2e138a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-set-duration-animation-finish.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#basic-shape-interpolation">
+<link rel="match" href="clip-path-animation-set-currenttime-ref.html">
+<style>
+  .container {
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    animation: clippath 10s -5s;
+    animation-fill-mode: none;
+    clip-path: inset(33% 33%);
+  }
+
+  @keyframes clippath {
+    0% {
+      clip-path: circle(50% at 50% 50%);
+    }
+
+    100% {
+      clip-path: circle(35% at 35% 35%);
+    }
+  }
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/web-animations/resources/timing-utils.js"></script>
+
+<body>
+  <div class="container">
+  </div>
+
+  <script>
+    let animation = document.getAnimations()[0];
+    animation.ready.then(() => {
+      // With the negative start delay of 5s, this should mean that the animation completes.
+      animation.effect.updateTiming({duration: 5000 - 1});
+
+      // Since the animation is finished, and animation-fill-mode is none,
+      // we should get the original style set in css .container rather than
+      // any animated style.
+      requestAnimationFrame(takeScreenshot);
+    });
+  </script>
+</body>
+
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-start-time-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-start-time-ref.html
new file mode 100644
index 0000000..067d779
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-start-time-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<style>
+.container {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  clip-path: circle(30% at 30% 30%);
+}
+</style>
+<body>
+<div class="container"></div>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-start-time.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-start-time.html
new file mode 100644
index 0000000..56ed807f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/animations/clip-path-animation-start-time.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://crbug.com/420284818">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-1/#basic-shape-interpolation">
+<link rel="match" href="clip-path-animation-start-time-ref.html">
+<style>
+.container {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  clip-path: inset(25% 25%);
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/web-animations/resources/timing-utils.js"></script>
+<body>
+<div id="anim" class="container"></div>
+
+<script>
+  let animation = new Animation(new KeyframeEffect(document.getElementById("anim"),
+    [
+      { clipPath: 'circle(30% at 30% 30%)' },
+      { clipPath: 'circle(50% at 50% 50%)' }
+    ],
+    {
+      duration: 10000,
+      easing: 'steps(2, jump-end)',
+    }), document.timeline);
+
+    animation.play();
+    animation.startTime = document.timeline.currentTime;
+
+    requestAnimationFrame(takeScreenshot);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/chrome-bug-1301281.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/chrome-bug-1301281.html
index 0c34e0889..bb4f1fc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/chrome-bug-1301281.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/chrome-bug-1301281.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1301281">
   <div style="columns:2; column-fill:auto; height:30px; line-height:20px; width:fit-content;">
@@ -13,7 +13,7 @@
         requestAnimationFrame(()=> {
           requestAnimationFrame(()=> {
             document.body.style.color = "blue";
-            document.documentElement.classList.remove("reftest-wait");
+            document.documentElement.classList.remove("test-wait");
           });
         });
       });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/floated-input-in-inline-next-column.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/floated-input-in-inline-next-column.html
index 1b84cd3..f1ada47 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/floated-input-in-inline-next-column.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/floated-input-in-inline-next-column.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1451185">
   <div id="container" style="opacity:0.0;">
@@ -12,7 +12,7 @@
     requestAnimationFrame(()=> {
       requestAnimationFrame(()=> {
         container.style.opacity = "1";
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/inline-float-parallel-flow.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/inline-float-parallel-flow.html
index 06e80f1..5280b8a6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/inline-float-parallel-flow.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/inline-float-parallel-flow.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1489177">
   <div style="columns:2; column-fill:auto; height:200px; line-height:20px; orphans:1; widows:1;">
@@ -16,7 +16,7 @@
     requestAnimationFrame(()=> {
       requestAnimationFrame(()=> {
         e57.style.display = "block";
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-linebreak-to-different-column.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-linebreak-to-different-column.html
index abe83ca1..d87881c3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-linebreak-to-different-column.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-linebreak-to-different-column.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1322739">
   <div id="container">
@@ -12,7 +12,7 @@
       requestAnimationFrame(()=> {
         mc.style.height = "80px";
         container.setAttribute("ontouchstart", "nonValidFunctionName()");
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html
index 13833ae..d63f919 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/move-newline-pre-text.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1386676">
   <div id="container" style="columns:10; column-fill:auto; height:30px; line-height:20px; orphans:1; widows:1; white-space:pre;">
@@ -14,7 +14,7 @@
         requestAnimationFrame(()=> {
           requestAnimationFrame(()=> {
             container.style.width = "88%";
-            document.documentElement.classList.remove("reftest-wait");
+            document.documentElement.classList.remove("test-wait");
           });
         });
       });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/oof-in-additional-column-before-spanner.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/oof-in-additional-column-before-spanner.html
index afdeabe1..fbfa0446 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/oof-in-additional-column-before-spanner.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/oof-in-additional-column-before-spanner.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1361902">
   <div style="columns:1;">
@@ -15,7 +15,7 @@
     requestAnimationFrame(()=>{
       requestAnimationFrame(()=>{
         elm.style.display = "none";
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
       });
     });
   </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/subpixel-scroll-crash.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/subpixel-scroll-crash.html
index 5a42908..254dfaf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/subpixel-scroll-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/subpixel-scroll-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
   <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
   <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1276319">
   <div style="columns:2; column-fill:auto; height:4000px;">
@@ -13,7 +13,7 @@
     var offset = 1000;
     function scrollEverSoSlightly() {
       if (offset > 1003) {
-        document.documentElement.classList.remove("reftest-wait");
+        document.documentElement.classList.remove("test-wait");
         return;
       }
       window.scrollTo(0, offset);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-010.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-010.html
index 1386b14..edeb898 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-010.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-010.html
@@ -4,7 +4,7 @@
 <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
 <link rel="match" href="reference/line-clamp-010-ref.html">
-<meta name="assert" content="When line-clamp is used with a number of lines, it should hide all lines after clamp, regardless of whether the box's height is set so they don't overflow">
+<meta name="assert" content="When line-clamp is used with a number of lines, it should hide all lines after that number, even if they fit in the box height.">
 <style>
 .clamp {
   line-clamp: 2;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html
index 953f0c4f..69effbc 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-011.tentative.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Overflow: when clamping by lines, lines before clamp are not hidden even when they overflow</title>
+<title>CSS Overflow: when clamping by lines, if the height doesn't fit that number of lines, the clamp point depends on the height instead</title>
 <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
 <link rel="match" href="reference/line-clamp-011-ref.html">
-<meta name="assert" content="When line-clamp is used with a number of lines, it should not hide any lines before clamp, regardless of whether the box's height is set so they overflow">
+<meta name="assert" content="When line-clamp is used with a number of lines while also having a set block size, whichever comes earlier takes precedence.">
 <style>
 .clamp {
   line-clamp: 4;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-019.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-019.html
similarity index 61%
rename from third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-019.tentative.html
rename to third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-019.html
index b39376d3..e956fe8 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-019.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-019.html
@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Overflow: line-clamp takes priority over -webkit-line-clamp</title>
+<title>CSS Overflow: line-clamp and -webkit-line-clamp compete in cascade order</title>
 <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
 <link rel="match" href="reference/webkit-line-clamp-005-ref.html">
-<meta name="assert" content="If both line-clamp and -webkit-line-clamp are present, line-clamp takes priority">
+<meta name="assert" content="line-clamp and -webkit-line-clamp are both shorthands for the same properties, so if both are present, whichever is greater in the cascade order wins.">
 <style>
 .clamp {
+  line-clamp: 2;
   display: -webkit-box;
   -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-  line-clamp: 4;
+  -webkit-line-clamp: 4;
   font: 16px / 32px serif;
   white-space: pre;
   padding: 0 4px;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-034.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-034.html
new file mode 100644
index 0000000..bb703dd2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-034.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: line-clamp and -webkit-line-clamp compete in cascade order, even without -webkit-box</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
+<link rel="match" href="reference/webkit-line-clamp-001-ref.html">
+<meta name="assert" content="line-clamp and -webkit-line-clamp are both shorthands for the same properties, so if both are present, whichever is greater in the cascade order wins. This is regardless of whether the properties that are needed for -webkit-line-clamp to do anything are present.">
+<style>
+.clamp {
+  line-clamp: 4;
+  -webkit-line-clamp: 4;
+  font: 16px / 32px serif;
+  white-space: pre;
+  background-color: yellow;
+}
+</style>
+<div class="clamp">Line 1
+Line 2
+Line 3
+Line 4
+Line 5</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-034.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-034.tentative.html
new file mode 100644
index 0000000..feb4aac6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-034.tentative.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: `line-clamp` with a number and a smaller max-height</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
+<link rel="match" href="reference/webkit-line-clamp-005-ref.html">
+<meta name="assert" content="If line-clamp is set to a number, and there is a (max-)height, the line-clamp container will clamp to whichever comes earlier.">
+<style>
+.clamp {
+  line-clamp: 6;
+  max-height: 4lh;
+  font: 16px / 32px serif;
+  white-space: pre;
+  background-color: yellow;
+  padding: 0 4px;
+}
+</style>
+<div class="clamp">Line 1
+Line 2
+Line 3
+Line 4
+Line 5
+Line 6
+Line 7</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-011.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-011.tentative.html
index 5051351..00076a5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-011.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-011.tentative.html
@@ -4,7 +4,7 @@
 <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
 <link rel="match" href="reference/line-clamp-auto-011-ref.html">
-<meta name="assert" content="When line-clamp: auto is used with max-height: 0, it should still show the first line">
+<meta name="assert" content="When line-clamp: auto is used with max-height: 0, it should not show any lines and its content box's intrinsic size should be zero">
 <style>
 .clamp {
   line-clamp: auto;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-025.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-025.tentative.html
new file mode 100644
index 0000000..7144be1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-025.tentative.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: abspos exactly at the clamp point is hidden</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
+<link rel="match" href="reference/line-clamp-auto-025-ref.html">
+<meta name="assert" content="The chosen clamp point with line-clamp: auto is after the last line or box where the box size doesn't overflow. If the clamp point follows a box, then no line has an ellipsis. However, only in-flow boxes count, so an abspos doesn't prevent a previous line from having the ellipsis.">
+<style>
+.clamp {
+  line-clamp: auto;
+  max-height: 4lh;
+  font: 16px / 32px serif;
+  padding: 0 4px;
+  background-color: yellow;
+}
+.inner {
+  white-space: pre-wrap;
+}
+.abspos {
+  position: absolute;
+  width: 100px;
+  height: 100px;
+  background-color: skyblue;
+}
+</style>
+<div class="clamp">
+<div class="inner">Line 1
+Line 2
+Line 3
+Line 4
+</div>
+<div class="abspos"></div>
+<div class="inner">Line 5
+Line 6</div>
+</div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-032.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-032.tentative.html
new file mode 100644
index 0000000..17c6981
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-032.tentative.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Overflow: `line-clamp: auto` margin collapsing accounts for self-collapsing boxes</title>
+<link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
+<link rel="match" href="reference/line-clamp-auto-032-ref.html">
+<meta name="assert" content="With `line-clamp: auto`, if a clamp point might fall inside a box, its margins are accounted for correctly. This is the case even for self-collapsing boxes before the clamp point.">
+<style>
+.clamp {
+  line-clamp: auto;
+  max-height: calc(4lh + 2 * 5px);
+  font: 16px / 32px serif;
+  background-color: orange;
+}
+.inner {
+  white-space: pre;
+  margin: 5px;
+  background-color: yellow;
+}
+.collapse-through {
+  margin: 5px;
+}
+.abspos {
+  position: absolute;
+  right: 0;
+  height: 100px;
+  width: 100px;
+  background-color: skyblue;
+}
+</style>
+
+<!--
+  The bottom margins of both the first `.inner` and of `.collapse-through` end
+  at the clamp boundary, since the bottom margin of `.inner` collapses through
+  `.collapse-through`. This also puts the static position of `.abspos` at the
+  clamp boundary, which means it will be visible.
+-->
+
+<div class="clamp">
+<div class="inner">Line 1
+Line 2
+Line 3
+Line 4</div>
+<div class="collapse-through"></div>
+<div class="abspos"></div>
+<div class="inner">Line 5
+Line 6
+Line 7
+Line 8</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-034.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-034.tentative.html
index 96fe675d..ebb676d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-034.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-034.tentative.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Overflow: `line-clamp: auto` clamp height after IFC</title>
+<title>CSS Overflow: `line-clamp: auto` clamp between IFCs</title>
 <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
-<link rel="match" href="reference/webkit-line-clamp-005-ref.html">
-<meta name="assert" content="With `line-clamp: auto`, if the clamp height is after an IFC, the clamp point will be set after the last line before that.">
+<link rel="match" href="reference/line-clamp-auto-034-ref.html">
+<meta name="assert" content="With `line-clamp: auto`, there can be a clamp point between two IFCs. In that case, no line will have an ellipsis.">
 <style>
 .clamp {
   line-clamp: auto;
@@ -28,5 +28,6 @@
 Line 2
 Line 3
 Line 4
-<div class="ifc red">Line 5
-Line 6</div>Line 7</div>
+<div class="ifc">Line 5
+Line 6</div><div class="ifc red">Line 7
+Line 8</div>Line 9</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-037.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-037.tentative.html
index 37b36666..4a2fc3c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-037.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/line-clamp-auto-037.tentative.html
@@ -3,7 +3,7 @@
 <title>CSS Overflow: `line-clamp: auto` with non-zero max-height that doesn't fit any content</title>
 <link rel="author" title="Andreu Botella" href="mailto:abotella@igalia.com">
 <link rel="help" href="https://drafts.csswg.org/css-overflow-4/#line-clamp">
-<link rel="match" href="reference/line-clamp-auto-037-ref.html">
+<link rel="match" href="reference/line-clamp-auto-011-ref.html">
 <meta name="assert" content="When line-clamp: auto is used with a max-height that isn't enough for any contained boxes or line boxes, then it should not show any content and its content box's intrinsic size should be zero">
 <style>
 .clamp {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html
index 04297ff..02ef71d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-011-ref.html
@@ -12,6 +12,5 @@
 </style>
 <div class="clamp">Line 1
 Line 2
-Line 3
-Line 4…</div>
+Line 3…</div>
 <p>Following content.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-011-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-011-ref.html
index 27a2e7b..5f7120e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-011-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-011-ref.html
@@ -3,13 +3,10 @@
 <title>CSS Reference</title>
 <style>
 .clamp {
-  height: 0;
-  font: 16px / 32px serif;
-  white-space: pre;
   background-color: yellow;
   border: 1px solid black;
   padding: 4px;
 }
 </style>
-<div class="clamp">Line 1…</div>
+<div class="clamp"></div>
 <p>Following content.</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-025-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-025-ref.html
new file mode 100644
index 0000000..c404f65
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-025-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  font: 16px / 32px serif;
+  padding: 0 4px;
+  background-color: yellow;
+}
+.inner {
+  white-space: pre-wrap;
+}
+.abspos {
+  position: absolute;
+  width: 100px;
+  height: 100px;
+  background-color: skyblue;
+}
+</style>
+
+<div class="clamp">
+<div class="inner">Line 1
+Line 2
+Line 3
+Line 4…
+</div>
+<div class="abspos"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-032-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-032-ref.html
new file mode 100644
index 0000000..4768c77d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-032-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  display: flow-root;
+  font: 16px / 32px serif;
+  background-color: orange;
+}
+.inner {
+  white-space: pre;
+  margin: 5px;
+  background-color: yellow;
+}
+.collapse-through {
+  margin: 5px;
+}
+.abspos {
+  position: absolute;
+  right: 0;
+  height: 100px;
+  width: 100px;
+  background-color: skyblue;
+}
+</style>
+
+<div class="clamp">
+<div class="inner">Line 1
+Line 2
+Line 3
+Line 4</div>
+<div class="collapse-through"></div>
+<div class="abspos"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-034-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-034-ref.html
new file mode 100644
index 0000000..8fae3b2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/line-clamp/reference/line-clamp-auto-034-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reference</title>
+<style>
+.clamp {
+  display: flow-root;
+  font: 16px / 32px serif;
+  white-space: pre;
+  padding: 0 4px;
+  background-color: yellow;
+}
+.ifc {
+  display: flow-root;
+  background-color: orange;
+}
+</style>
+
+<div class="clamp">Line 1
+Line 2
+Line 3
+Line 4
+<div class="ifc">Line 5
+Line 6</div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-dynamic-crash.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-dynamic-crash.html
index 22c5b7d2..8512ef5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-dynamic-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-dynamic-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <style>
   #container {
     columns: 1;
@@ -22,7 +22,7 @@
   requestAnimationFrame(() => {
     requestAnimationFrame(() => {
       container.style.width = "501px";
-      document.documentElement.classList.remove("reftest-wait");
+      document.documentElement.classList.remove("test-wait");
     });
   });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-focus-scroll-crash.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-focus-scroll-crash.html
index 97b3be1e..ed92b21 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-focus-scroll-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-focus-scroll-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <meta charset="utf-8">
 <link rel="help" href="crbug.com/421471058">
 <script src="/resources/testdriver.js"></script>
@@ -54,7 +54,7 @@
       .send();
     // With a focused scroll marker, scroll to next target.
     document.querySelector('#scroller').scrollLeft = 600;
-    document.documentElement.classList.remove('reftest-wait');
+    document.documentElement.classList.remove('test-wait');
   }
   run();
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-ancestor-crash.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-ancestor-crash.html
index 451e9e9..4f3c277 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-ancestor-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-ancestor-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <meta charset="utf-8">
 <title>::scroll-markers with content-visibility: hidden ancestors, getBoundingClientRect crash</title>
 <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-pseudo">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-crash.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-crash.html
index 7e6fee2..fd194c5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-marker-with-content-visibility-hidden-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <meta charset="utf-8">
 <title>::scroll-markers with content-visibility: hidden ancestors, getBoundingClientRect crash</title>
 <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-pseudo">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-markers-resize-crash.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-markers-resize-crash.html
index 64d45fa..8a16267 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-markers-resize-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scroll-markers-resize-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <meta charset="utf-8">
 <title>CSS Test: ::scroll-markers don't crash on resize</title>
 <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-marker-pseudo">
@@ -30,7 +30,7 @@
     document.body.offsetTop;
     wheee.scrollLeft = 100;
     wheee.style.width = "500px";
-    document.documentElement.classList.remove("reftest-wait");
+    document.documentElement.classList.remove("test-wait");
   </script>
 
 </html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/overlay/overlay-popover-backdrop-crash.html b/third_party/blink/web_tests/external/wpt/css/css-position/overlay/overlay-popover-backdrop-crash.html
index f59fc5d..1180dd6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-position/overlay/overlay-popover-backdrop-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/overlay/overlay-popover-backdrop-crash.html
@@ -1,8 +1,7 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <title>CSS Position Test: Chrome crash for ::backdrop transitioning overlay for popover</title>
 <link rel="help" href="https://crbug.com/1446479">
-<script src="/common/reftest-wait.js"></script>
 <style>
   #popover {
     transition: overlay 60s step-end;
@@ -19,7 +18,7 @@
     popover.showPopover();
     requestAnimationFrame(() => {
       popover.hidePopover();
-      takeScreenshot();
+      document.documentElement.removeAttribute("class");
     });
   });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/reload-crash.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/reload-crash.html
index a2bf11b..c28bd36 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/reload-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/navigation/reload-crash.html
@@ -1,14 +1,13 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <title>View transitions: reload crash</title>
 <link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
 <link rel="author" href="mailto:vmpstr@chromium.org">
-<script src="/common/reftest-wait.js"></script>
 <script>
 onload = () => requestAnimationFrame(() => requestAnimationFrame(() => requestAnimationFrame(() => {
   let run = (new URLSearchParams(window.location.search)).get('run') || 0;
   if (run > 5) {
-    takeScreenshot();
+    document.documentElement.removeAttribute("class");
   } else {
     const url = window.location.href.split('?')[0];
     window.location.href = url + `?run=${run + 1}`;
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html
index d228be8..dfcac9e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-element-display-none-crash.html
@@ -1,10 +1,9 @@
 <!DOCTYPE html>
-<html class=reftest-wait>
+<html class=test-wait>
 <title>View transitions: html display none</title>
 <link rel="help" href="https://drafts.csswg.org/css-view-transitions-1/">
 <link rel="author" href="mailto:vmpstr@chromium.org">
 
-<script src="/common/reftest-wait.js"></script>
 <style>
 html {
   display: none;
@@ -12,11 +11,18 @@
 </style>
 
 <script>
-failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+function finish() {
+  document.documentElement.removeAttribute("class");
+}
 
 async function runTest() {
-  document.startViewTransition().finished.then(takeScreenshot, takeScreenshot);
+  if (!document.startViewTransition) {
+    document.body.textContent = "Precondition Failed: Missing document.startViewTransition";
+    finish();
+    return;
+  }
 
+  document.startViewTransition().finished.then(finish, finish);
 }
 onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-reconstruct-frame-tree-crash.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-reconstruct-frame-tree-crash.html
index bff9a16..108f3c1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-reconstruct-frame-tree-crash.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/root-reconstruct-frame-tree-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1966682">
 <script>
   window.addEventListener("load", async () => {
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/shorthand-values.html b/third_party/blink/web_tests/external/wpt/css/cssom/shorthand-values.html
index f831cba..861e4f92 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom/shorthand-values.html
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/shorthand-values.html
@@ -43,6 +43,10 @@
         'padding-top: 1px; padding-right: 2px; padding-bottom: 3px; padding-left: 4px;': 'padding: 1px 2px 3px 4px;'
       }
 
+      if (CSS.supports("-webkit-line-clamp: none") && CSS.supports("line-clamp: none")) {
+        tests["-webkit-line-clamp: none;"] = "line-clamp: none;";
+      }
+
       for (let test in tests) {
         test_shorthand_serialization(test, tests[test]);
       }
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/allowed-refresh-initiators.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/allowed-refresh-initiators.https.html
new file mode 100644
index 0000000..bef2d55
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/allowed-refresh-initiators.https.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="helper.js" type="module"></script>
+
+<script type="module">
+  import { expireCookie, documentHasCookie, waitForCookie, addCookieAndSessionCleanup, setupShardedServerState, configureServer } from "./helper.js";
+
+  // Create an iframe that fetches URLs on demand via postMessage.
+  async function createFrame(url) {
+    const frame = document.createElement('iframe');
+    const promise = new Promise((resolve, reject) => {
+      frame.onload = () => resolve(frame);
+      frame.onerror = () => {
+        reject();
+      };
+    });
+    frame.src = url;
+    document.body.appendChild(frame);
+    return promise;
+  }
+
+  async function crossSiteFetch(frame, url) {
+    let promise = new Promise((resolve) => {
+      const listener = (event) => {
+        window.removeEventListener("message", listener);
+        resolve(event.data);
+      };
+      window.addEventListener("message", listener);
+    });
+    frame.contentWindow.postMessage(url, "*");
+    return promise;
+  }
+
+  async function runTest(t, origin, refresh_expected) {
+    await setupShardedServerState({crossSite: true});
+    const expectedCookieAndValue = "auth_cookie=abcdef0123";
+    // Override the attributes to be SameSite=None.
+    const expectedCookieAttributes = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=None;Secure`;
+    const expectedCookieAndAttributes = `${expectedCookieAndValue};${expectedCookieAttributes}`;
+    addCookieAndSessionCleanup(t);
+
+    configureServer({ allowedRefreshInitiators: [get_host_info().NOTSAMESITE_HOST],
+                      cookieDetails: [ {attributes: expectedCookieAttributes} ],
+                    });
+
+    // Prompt starting a session, and wait until registration completes.
+    const loginResponse = await fetch('login.py');
+    assert_equals(loginResponse.status, 200);
+    await waitForCookie(expectedCookieAndValue, /*expectCookie=*/true);
+
+    const frame = await createFrame(`${origin}/device-bound-session-credentials/url_fetcher.html`);
+
+    // Expire the cookie, and check whether a refresh has occurred.
+    expireCookie(expectedCookieAndAttributes);
+    assert_false(documentHasCookie(expectedCookieAndValue));
+
+    const authStatusAfterExpiry = await crossSiteFetch(frame, `${location.protocol}//${location.host}/device-bound-session-credentials/verify_authenticated.py`);
+    assert_equals(authStatusAfterExpiry, refresh_expected ? 200 : 401);
+    assert_equals(documentHasCookie(expectedCookieAndValue), refresh_expected);
+  }
+
+  promise_test(async t => {
+    await runTest(t, location.origin, /*refresh_expected=*/true);
+  }, "An established session refreshes when initated by the owning site");
+
+  promise_test(async t => {
+    await runTest(t, get_host_info().HTTPS_NOTSAMESITE_ORIGIN, /*refresh_expected=*/true);
+  }, "An established session refreshes when initated by a host in allowed_refresh_initiators");
+
+  promise_test(async t => {
+    await runTest(t, get_host_info().HTTPS_OTHER_NOTSAMESITE_ORIGIN, /*refresh_expected=*/false);
+  }, "An established session does not refresh when initated by a host not in allowed_refresh_initiators");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/clear-site-data.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/clear-site-data.https.html
index 94f2d96..ba76a90 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/clear-site-data.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/clear-site-data.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session ended with Clear-Site-Data</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
@@ -23,7 +22,7 @@
     const endSessionResponse = await fetch('end_session_via_clear_site_data.py');
     assert_equals(endSessionResponse.status, 200);
     // Need to set up the state again because all cookies were cleared.
-    await setupShardedServerState(testId);
+    await setupShardedServerState({testId});
 
     // Expire the cookie, and confirm it does not get refreshed.
     expireCookie(expectedCookieAndAttributes);
@@ -48,7 +47,7 @@
     const endSessionResponse = await fetch('end_session_via_clear_site_data.py', {method: 'POST', body: '"storage"'});
     assert_equals(endSessionResponse.status, 200);
     // Need to set up the state again because all cookies were cleared.
-    await setupShardedServerState(testId);
+    await setupShardedServerState({testId});
 
     // Expire the cookie, and confirm it does not get refreshed.
     expireCookie(expectedCookieAndAttributes);
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/create-session.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/create-session.https.html
index 13e17de..1ed8ac5e 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/create-session.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/create-session.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC create a basic session</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/credentials-matching.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/credentials-matching.https.html
index 28af915..cdbfa67 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/credentials-matching.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/credentials-matching.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC credentials matching</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/debug-header.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/debug-header.https.html
index 4f384bf..b3e09e7 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/debug-header.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/debug-header.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session sends debug header</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/get-host-info.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/fetch-no-credentials.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/fetch-no-credentials.https.html
index 4cac685..bd87e68 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/fetch-no-credentials.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/fetch-no-credentials.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC does not refresh cross-site fetch without credentials</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/get-host-info.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/helper.js b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/helper.js
index 58b7a5f..e364e2e 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/helper.js
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/helper.js
@@ -49,10 +49,9 @@
   assert_equals(response.status, 200);
 }
 
-export async function setupShardedServerState(testId) {
-  const obj = {};
-  if (testId !== undefined) {
-    obj.testId = testId;
+export async function setupShardedServerState(obj) {
+  if (obj === undefined) {
+    obj = {};
   }
   const response = await fetch('setup_sharded_server_state.py', {
     method: 'POST',
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/include-site.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/include-site.https.html
index 6eaf522..3441acfc 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/include-site.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/include-site.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session over multiple origins</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-credentials.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-credentials.https.html
index 57fe9294..54fc182b 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-credentials.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-credentials.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session with multiple credentials</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-registrations.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-registrations.https.html
index ef024bd..fb0ce50 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-registrations.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/multiple-registrations.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC multiple registrations</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/not-secure-connection.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/not-secure-connection.html
index b2c99b13..9bc736f 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/not-secure-connection.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/not-secure-connection.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>No DBSC if connection is HTTP</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-does-not-send-challenge.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-does-not-send-challenge.https.html
index d882cfe..a53245c 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-does-not-send-challenge.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-does-not-send-challenge.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC refresh does not send back Sec-Session-Challenge</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-replaces-config.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-replaces-config.https.html
index d9e8ff2..74264888 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-replaces-config.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-replaces-config.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC refresh sends back new session config</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-with-continue-false.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-with-continue-false.https.html
index 7814a49..1953af5 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-with-continue-false.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/refresh-with-continue-false.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session ended with continue:false</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/registration-sends-challenge.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/registration-sends-challenge.https.html
index d95fa42..ab8d033 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/registration-sends-challenge.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/registration-sends-challenge.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC registration sends back Sec-Session-Challenge</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/resolving-urls.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/resolving-urls.https.html
index 79f1594..bb10cf5 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/resolving-urls.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/resolving-urls.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session configuration resolving URLs</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session-cookie-has-no-attributes.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session-cookie-has-no-attributes.https.html
index 734b4d1a..5bf07ab 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session-cookie-has-no-attributes.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session-cookie-has-no-attributes.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC session cookie has only default attributes</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session_manager.py b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session_manager.py
index 98e01309..779d1435 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session_manager.py
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/session_manager.py
@@ -46,6 +46,7 @@
         self.include_site = True
         self.refresh_endpoint_unavailable = False
         self.response_session_id_override = None
+        self.allowed_refresh_initiators = ["*"]
 
     def next_session_id(self):
         return len(self.session_to_key_map)
@@ -127,6 +128,10 @@
         if response_session_id_override is not None:
             self.response_session_id_override = response_session_id_override
 
+        allowed_refresh_initiators = configuration.get("allowedRefreshInitiators")
+        if allowed_refresh_initiators is not None:
+            self.allowed_refresh_initiators = allowed_refresh_initiators
+
     def get_should_refresh_end_session(self):
         return self.should_refresh_end_session
 
@@ -198,7 +203,8 @@
                     { "type": "exclude", "domain": request.url_parts.hostname, "path": "/device-bound-session-credentials/set_cookie.py" },
                 ]
             },
-            "credentials": self.get_sessions_instructions_response_credentials(session_id, request)
+            "credentials": self.get_sessions_instructions_response_credentials(session_id, request),
+            "allowed_refresh_initiators": self.allowed_refresh_initiators,
         }
         headers = self.get_session_instructions_response_set_cookie_headers(session_id, request) + [
             ("Content-Type", "application/json"),
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-authorization.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-authorization.https.html
index 26969d4..7e2d8a0 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-authorization.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-authorization.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC authorization value sent</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-early-challenge.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-early-challenge.https.html
index a6d032f9..22166c8 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-early-challenge.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-early-challenge.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC early challenge set</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-origin.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-origin.https.html
index 817d5cda..f56778a 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-origin.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC scope origin set</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-specification.https.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-specification.https.html
index 8ec125d7..5a36831 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-specification.https.html
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/set-scope-specification.https.html
@@ -1,6 +1,5 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>DBSC scope specification set</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="helper.js" type="module"></script>
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/setup_sharded_server_state.py b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/setup_sharded_server_state.py
index f3e6029e..57e935e 100644
--- a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/setup_sharded_server_state.py
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/setup_sharded_server_state.py
@@ -9,4 +9,13 @@
     if test_id is None:
         test_id = session_manager.initialize_test()
 
-    return (200, [("Set-Cookie", f"test_id={test_id}")], "")
+    headers = [("Set-Cookie", f"test_id={test_id}")]
+    # Cross-site tests (e.g. allowed-refresh-initiators.https.html) require a
+    # SameSite=None cookie, which must also be Secure. But
+    # not-secure-connection.html cannot have a Secure cookie, so we need to make
+    # the attributes conditional on the test.
+    cross_site = request_body.get("crossSite")
+    if cross_site is not None and cross_site:
+        headers = [("Set-Cookie", f"test_id={test_id};SameSite=None;Secure")]
+
+    return (200, headers, "")
diff --git a/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/url_fetcher.html b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/url_fetcher.html
new file mode 100644
index 0000000..be1cb979
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/device-bound-session-credentials/url_fetcher.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<body>
+  <script>
+    'use strict';
+
+    window.addEventListener("message", async (event) => {
+      const response = await fetch(event.data, {credentials: "include"});
+      event.source.postMessage(response.status, "*");
+    });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt b/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt
index e6017b50..70beb572 100644
--- a/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/digital-credentials/get.tentative.https-expected.txt
@@ -1,6 +1,4 @@
 This is a testharness.js-based test.
-[FAIL] Calling navigator.credentials.get() without a digital member same origin.
-  assert_unreached: Should have rejected: undefined Reached unreachable code
 [FAIL] navigator.credentials.get() API rejects if there are no credential request.
   assert_unreached: Should have rejected: undefined Reached unreachable code
 [FAIL] navigator.credentials.get() API rejects if there are no credential request for same-origin iframe.
diff --git a/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md b/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md
index eed5225..afbbeb6 100644
--- a/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md
+++ b/third_party/blink/web_tests/external/wpt/docs/running-tests/safari.md
@@ -1,47 +1,34 @@
 # Safari
 
-To run Safari on macOS, some manual setup is required. Some steps are different
-for Safari and Safari Technology Preview.
+To run Safari on macOS, some manual setup is required.
 
-  * Allow Safari to be controlled by SafariDriver:
-    * `safaridriver --enable` or
-    * `"/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --enable`
+To enable Remote Automation, run either:
 
-  * Allow pop-up windows:
-    * `defaults write com.apple.Safari WebKitJavaScriptCanOpenWindowsAutomatically 1` or
-    * `defaults write com.apple.SafariTechnologyPreview WebKitJavaScriptCanOpenWindowsAutomatically 1`
+  * `safaridriver --enable`, for Safari, or
+  * `"/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" --enable`,
+    for Safari Technology Preview.
 
-  * Turn on additional experimental features Safari Technology Preview:
-    * `defaults write com.apple.SafariTechnologyPreview ExperimentalServerTimingEnabled 1`
-
-  * Trust the certificate:
-    * `security add-trusted-cert -k "$(security default-keychain | cut -d\" -f2)" tools/certs/cacert.pem`
-
-  * Set `no_proxy='*'` in your environment. This is a
-    workaround for a known
-    [macOS High Sierra issue](https://github.com/web-platform-tests/wpt/issues/9007).
+You must also ensure you have
+[configured the `hosts` file](from-local-system.html#hosts-file-setup).
 
 Now, run the tests using the `safari` product:
 ```
 ./wpt run safari [test_list]
 ```
 
-This will use the `safaridriver` found on the path, which will be stable Safari.
-To run Safari Technology Preview instead, use the `--channel=preview` argument:
+This will default to `--channel=preview` and run Safari Technology Preview.
+To run the system Safari instead, use the `--channel=stable` argument:
 ```
-./wpt run --channel=preview safari [test_list]
+./wpt run --channel=stable safari [test_list]
 ```
 
 ## Debugging
 
 To debug problems with `safaridriver`, add the `--webdriver-arg=--diagnose`
-argument:
+option:
 ```
 ./wpt run --channel=preview --webdriver-arg=--diagnose safari [test_list]
 ```
 
 The logs will be in `~/Library/Logs/com.apple.WebDriver/`.
-See `man safaridriver` for more information.
-
-To enable safaridriver diagnostics in Azure Pipelines, set
-`safaridriver_diagnose` to `true` in `.azure-pipelines.yml`.
+See `man 1 safaridriver` for more information.
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/css-transition-cross-document.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/css-transition-cross-document.html
index de30e9e..b165d829 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/css-transition-cross-document.html
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/css-transition-cross-document.html
@@ -4,7 +4,11 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <body>
-  <iframe id="iframe">
+  <script>
+    let iframeLoadResolve;
+    let iframeLoadPromise = new Promise((r) => { iframeLoadResolve = r; });
+  </script>
+  <iframe id="iframe" onload="iframeLoadResolve()">
   </iframe>
   <section id="new-parent">
   </section>
@@ -28,6 +32,7 @@
   </style>
   <script>
     promise_test(async t => {
+      await iframeLoadPromise;
       const iframe = document.querySelector("#iframe");
       const style = document.querySelector("#style");
       iframe.contentDocument.head.append(style.cloneNode(true));
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/iframe-document-preserve.window.js b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/iframe-document-preserve.window.js
index 4f9fa75..9edc44a 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/iframe-document-preserve.window.js
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/iframe-document-preserve.window.js
@@ -6,14 +6,23 @@
   const iframe = document.createElement('iframe');
   t.add_cleanup(() => iframe.remove());
 
-  iframe.onload = e => iframeLoadCounter++;
+  const loadPromise = new Promise((resolve) => {
+    iframe.onload = () => {
+      iframeLoadCounter++;
+      resolve()
+    };
+  });
+
   div.append(iframe);
   document.body.append(div);
+  await loadPromise;
   assert_equals(iframeLoadCounter, 1, "iframe loads");
 
   const innerDocument = iframe.contentDocument;
   assert_true(innerDocument !== null, "about:blank Document is reachable");
 
+  iframe.onload = () => iframeLoadCounter++;
+  await new Promise(resolve => t.step_timeout(resolve, 50));
   document.body.moveBefore(iframe, null);
   assert_equals(iframe.contentDocument, innerDocument, "Document is preserved");
   assert_equals(iframeLoadCounter, 1, "iframe does not reload");
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-from-light-to-shadow.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-from-light-to-shadow.html
new file mode 100644
index 0000000..d0ca568
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-from-light-to-shadow.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+    <div id="host">
+        <template shadowRootMode="open">
+            <div><div style="display: none;"><slot></slot></div></div>
+        </template>
+    </div>
+    <span id="span">Text in light DOM</span>
+<script>
+    test(t => {
+        const host = document.getElementById("host");
+        const span = document.getElementById("span");
+        assert_true(span.getBoundingClientRect().width > 0);
+        host.moveBefore(span, null);
+        assert_true(span.getBoundingClientRect().width == 0);
+    });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/selection-preserve.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/selection-preserve.html
index cb49e19..25ff3d2 100644
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/selection-preserve.html
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/selection-preserve.html
@@ -34,6 +34,7 @@
 
   await select_range(t, text, text);
 
+  // XXX This test seems to rely on Chromium internal behavior!
   // Don't first verify that `getSelection().anchorNode` is the expected
   // `<span id=text>` node that was selected above. If we did that, then at
   // least in Chromium browsers, this would generate a new Range capturing the
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list-002.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list-002.html
index 23f0496..972824c 100644
--- a/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list-002.html
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list-002.html
@@ -1,4 +1,4 @@
-<html class="test-wait reftest-wait">
+<html class="test-wait">
 <style>
 #a {
   float: none;
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list.html
index f7c7a74..0535224 100644
--- a/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list.html
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/caret-display-list.html
@@ -1,4 +1,4 @@
-<html class="test-wait reftest-wait">
+<html class="test-wait">
 <style>
 * {
   backdrop-filter: hue-rotate(0deg);
diff --git a/third_party/blink/web_tests/external/wpt/editing/crashtests/designMode-caret-change.html b/third_party/blink/web_tests/external/wpt/editing/crashtests/designMode-caret-change.html
index be80afd..685fd17 100644
--- a/third_party/blink/web_tests/external/wpt/editing/crashtests/designMode-caret-change.html
+++ b/third_party/blink/web_tests/external/wpt/editing/crashtests/designMode-caret-change.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="test-wait reftest-wait">
+<html class="test-wait">
 <style>
 button {
   background-repeat: no-repeat;
diff --git a/third_party/blink/web_tests/external/wpt/editing/data/insertparagraph.js b/third_party/blink/web_tests/external/wpt/editing/data/insertparagraph.js
index 8e72eb5..6583152 100644
--- a/third_party/blink/web_tests/external/wpt/editing/data/insertparagraph.js
+++ b/third_party/blink/web_tests/external/wpt/editing/data/insertparagraph.js
@@ -257,12 +257,14 @@
     {"defaultparagraphseparator":[false,false,"div",false,false,"p"],"insertparagraph":[false,false,"",false,false,""]}],
 ["<h1>foo[]<br></h1>",
     [["defaultparagraphseparator","div"],["insertparagraph",""]],
-    "<h1>foo</h1><div>{}<br></div>",
+    ["<h1>foo</h1><div><br></div>",
+     "<h1>foo<br></h1><div><br></div>"],
     [true,true],
     {"defaultparagraphseparator":[false,false,"p",false,false,"div"],"insertparagraph":[false,false,"",false,false,""]}],
 ["<h1>foo[]<br></h1>",
     [["defaultparagraphseparator","p"],["insertparagraph",""]],
-    "<h1>foo</h1><p>{}<br></p>",
+    ["<h1>foo</h1><p><br></p>",
+     "<h1>foo<br></h1><p><br></p>"],
     [true,true],
     {"defaultparagraphseparator":[false,false,"div",false,false,"p"],"insertparagraph":[false,false,"",false,false,""]}],
 ["<h1>foo[]bar</h1>",
diff --git a/third_party/blink/web_tests/external/wpt/editing/run/insertparagraph_1-1000-expected.txt b/third_party/blink/web_tests/external/wpt/editing/run/insertparagraph_1-1000-expected.txt
index c2132fd..7102055 100644
--- a/third_party/blink/web_tests/external/wpt/editing/run/insertparagraph_1-1000-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/editing/run/insertparagraph_1-1000-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 49 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 47 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] [["defaultparagraphseparator","div"],["insertparagraph",""]] "foo[bar]baz" compare innerHTML
   assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div>foo</div><div>baz</div>" but got "foo<div>baz</div>"
 [FAIL] [["defaultparagraphseparator","p"],["insertparagraph",""]] "foo[bar]baz" compare innerHTML
@@ -70,10 +70,6 @@
   assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<dl><dt>foo</dt><dd>bar</dd><dt><br></dt></dl>" but got "<dl><dt>foo</dt><dd>bar</dd><dd><br></dd></dl>"
 [FAIL] [["insertparagraph",""]] "<dl><dt>foo<dd>bar[]<br></dl>" compare innerHTML
   assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<dl><dt>foo</dt><dd>bar</dd><dt><br></dt></dl>" but got "<dl><dt>foo</dt><dd>bar<br></dd><dd><br></dd></dl>"
-[FAIL] [["defaultparagraphseparator","div"],["insertparagraph",""]] "<h1>foo[]<br></h1>" compare innerHTML
-  assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<h1>foo</h1><div><br></div>" but got "<h1>foo<br></h1><div><br></div>"
-[FAIL] [["defaultparagraphseparator","p"],["insertparagraph",""]] "<h1>foo[]<br></h1>" compare innerHTML
-  assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<h1>foo</h1><p><br></p>" but got "<h1>foo<br></h1><p><br></p>"
 [FAIL] [["insertparagraph",""]] "<ol><li>foo[]<br></ol>" compare innerHTML
   assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li><br></li></ol>" but got "<ol><li>foo<br></li><li><br></li></ol>"
 [FAIL] [["defaultparagraphseparator","div"],["insertparagraph",""]] "<p>foo[]<br></p>" compare innerHTML
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
index 95066cd..d4945a0 100644
--- 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
@@ -5,7 +5,7 @@
 
 See also:
 
-* [Explainer](https://github.com/explainers-by-googlers/local-network-access)
+* [Spec](https://wicg.github.io/local-network-access/)
 
 Local Network Access replaced [Private Network
-Access](https://wicg.github.io/local-network-access/).
+Access](https://wicg.github.io/private-network-access/).
diff --git a/third_party/blink/web_tests/external/wpt/fullscreen/crashtests/chrome-1312699.html b/third_party/blink/web_tests/external/wpt/fullscreen/crashtests/chrome-1312699.html
index c783b0d9..180f366 100644
--- a/third_party/blink/web_tests/external/wpt/fullscreen/crashtests/chrome-1312699.html
+++ b/third_party/blink/web_tests/external/wpt/fullscreen/crashtests/chrome-1312699.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <link rel="help" href="https://crbug.com/1312699">
 <script src="/resources/testdriver.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
@@ -9,7 +9,7 @@
     let video = document.querySelector("video");
     await video.requestFullscreen();
     video.width = null;
-    document.documentElement.classList.remove("reftest-wait");
+    document.documentElement.classList.remove("test-wait");
   }
   document.addEventListener("click", () => crash(), false);
 
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html
index 1baf784..884daa75 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas-worker-font-load-crash.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="test-wait reftest-wait">
+<html class="test-wait">
 <script>
   let url = URL.createObjectURL(new Blob([`
     let font = new FontFace('Ahem', 'url(/fonts/Ahem.ttf)');
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/partial-updates/tentative/patch-self.html b/third_party/blink/web_tests/external/wpt/html/dom/partial-updates/tentative/patch-self.html
new file mode 100644
index 0000000..e5938b6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/partial-updates/tentative/patch-self.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8" />
+<title>HTML partial updates - patch stream</title>
+<link rel=help href="https://github.com/WICG/declarative-partial-updates">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="placeholder">
+</div>
+<style id="style"></style>
+<p id="target"></p>
+<script>
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    const writable = placeholder.patchSelf();
+    assert_true(writable instanceof WritableStream, "node.patchSelf() returns a writable stream");
+    const response = new Response("Content", {headers: {"Content-Type": "text/html"}});
+    response.body.pipeTo(writable);
+    assert_true(placeholder.currentPatch instanceof PatchStatus, "currentPatch should be a PatchStatus right after connecting a stream");
+    await placeholder.currentPatch.finished;
+    assert_equals(placeholder.textContent, "Content");
+    assert_equals(placeholder.currentPatch, null);
+    assert_true(response.bodyUsed);
+}, "streaming a response into node.patchSelf()");
+
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    const writable = placeholder.patchSelf();
+    assert_true(writable instanceof WritableStream, "node.patchSelf() returns a writable stream");
+    const writer = writable.getWriter();
+    await writer.write("Text");
+    const {currentPatch} = placeholder;
+    assert_true(currentPatch instanceof PatchStatus, "currentPatch should be a PatchStatus right after connecting a stream");
+    writer.close();
+    await currentPatch.finished;
+    assert_equals(placeholder.textContent, "Text");
+    assert_equals(placeholder.currentPatch, null);
+}, "streaming text directly into node.patchSelf()");
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    placeholder.innerHTML = "Before";
+    const writable = placeholder.patchSelf();
+    assert_true(writable instanceof WritableStream, "node.patchSelf() returns a writable stream");
+    const writer = writable.getWriter();
+    const {currentPatch} = placeholder;
+    const reason = await writer.write(Symbol("sym")).catch(e => Promise.resolve(e));
+    const result = await currentPatch.finished.then(() => Promise.resolve("ok")).catch(e => Promise.resolve(e));
+    assert_true(result instanceof DOMException, `Expected a DOMException and received ${result}`);
+    assert_equals(result.name, "DataError");
+    assert_equals(result, reason);
+    assert_equals(placeholder.textContent, "");
+    assert_equals(placeholder.currentPatch, null);
+}, "streaming a Symbol directly into node.patchSelf()");
+
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    const writable = placeholder.patchSelf();
+    assert_true(writable instanceof WritableStream, "node.patchSelf() returns a writable stream");
+    const writer = writable.getWriter();
+    await writer.write(12345);
+    const {currentPatch} = placeholder;
+    writer.close();
+    await currentPatch.finished;
+    assert_equals(placeholder.textContent, "12345");
+    assert_equals(placeholder.currentPatch, null);
+}, "streaming numbers directly into node.patchSelf()");
+
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    const writable = placeholder.patchSelf();
+    assert_true(writable instanceof WritableStream, "node.patchSelf() returns a writable stream");
+    const writer = writable.getWriter();
+    await writer.write(null);
+    await writer.write(" ");
+    await writer.write(undefined);
+    const {currentPatch} = placeholder;
+    writer.close();
+    await currentPatch.finished;
+    assert_equals(placeholder.textContent, "null undefined");
+    assert_equals(placeholder.currentPatch, null);
+}, "streaming null or undefined directly into node.patchSelf()");
+
+promise_test(async t => {
+    const style = document.querySelector("#style");
+    const writable = style.patchSelf();
+    const response = new Response("#target { color: rgba(100, 0, 100); }", {headers: {"Content-Type": "text/css"}});
+    await response.body.pipeTo(writable);
+    assert_equals(getComputedStyle(document.querySelector("#target")).color, "rgb(100, 0, 100)");
+}, "patchSelf() can stream into elements that receive raw text like <style>");
+
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    const writable = placeholder.patchSelf();
+    const writer = writable.getWriter();
+    const encoder = new TextEncoder();
+    await writer.write(encoder.encode("ABC"));
+    const patch = placeholder.currentPatch;
+    await writer.abort("abort-reason");
+    await writer.write(encoder.encode("DEF")).catch(() => {});
+    const result = await patch.finished.then(() =>
+        Promise.resolve("success")).catch(e => Promise.resolve(e));
+    assert_equals(placeholder.textContent, "ABC");
+    assert_equals(result, "abort-reason");
+}, "Aborting A node.patchSelf() stream");
+
+promise_test(async t => {
+    const placeholder = document.querySelector("#placeholder");
+    let writable = placeholder.patchSelf();
+    assert_true(writable instanceof WritableStream, "node.patchSelf() returns a writable stream");
+    const response1 = new Response("content1", {headers: {"Content-Type": "text/html"}});
+    const response2 = new Response("content2", {headers: {"Content-Type": "text/html"}});
+    response1.body.pipeTo(writable);
+    const first_patch = placeholder.currentPatch;
+    writable = placeholder.patchSelf();
+    const {currentPatch} = placeholder;
+    response2.body.pipeTo(writable);
+    await promise_rejects_dom(t, "AbortError", first_patch.finished);
+    await currentPatch.finished;
+    assert_equals(placeholder.textContent, "content2");
+    assert_equals(placeholder.currentPatch, null);
+}, "A newer patch aborts the old one with an AbortError");
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/023.html b/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/023.html
index 4765d792f..7109fde 100644
--- a/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/023.html
+++ b/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/023.html
@@ -6,42 +6,51 @@
 <script src="/resources/testdriver-actions.js"></script>
 <script src="../resources/test-helper.js"></script>
 <head>
-<title>Dropping image on horizontal object scrollbar</title>
-<style type="text/css">
-p:first-child
-  {padding-left:1em;}
-object
-  {height:3em;
-  width:4em;}
-img
-  {width:5px;
-  height:5px;}
-</style>
-<script type="application/ecmascript">
-function dragImage()
-  {event.dataTransfer.effectAllowed = 'copy';}
-function dropImage(event)
-  {document.querySelector('p + p').firstChild.nodeValue = 'PASS';}
-</script>
+  <title>Dropping image on horizontal object scrollbar</title>
+  <style type="text/css">
+    p:first-child {
+      padding-left: 1em;
+    }
+
+    object {
+      height: 3em;
+      width: 4em;
+    }
+
+    img {
+      width: 5px;
+      height: 5px;
+    }
+  </style>
+  <script>
+    function dragImage() {
+      event.dataTransfer.effectAllowed = 'copy';
+    }
+  </script>
 </head>
 <body ondragenter="event.preventDefault()" ondragover="return false">
-<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAEElEQVR42mNgaGD4D8YwBgAw9AX9Y9zBwwAAAABJRU5ErkJggg==" alt="PNG green pixel" ondragstart="dragImage()"/></p>
-<p>Drag little square above and drop it on horizontal scrollbar. Word PASS should appear once you drop it.</p>
-<object type="application/xhtml+xml" data="helper-drop-horizontal-scrollbar.xhtml">XHTML document</object>
-<script>
-async function test(){
-  await new Promise(loaded => window.addEventListener("load", loaded));
-  const img = document.querySelector('img');
-  const object = document.querySelector('object');
-  function onDropCallBack(event) {
-    dropImage(event);
-    assert_equals('PASS', document.querySelector('p + p').firstChild.nodeValue);
-    return true;
-  }
+  <p><img
+      src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAEElEQVR42mNgaGD4D8YwBgAw9AX9Y9zBwwAAAABJRU5ErkJggg=="
+      alt="PNG green pixel" ondragstart="dragImage()" /></p>
+  <p>Drag little square above and drop it on horizontal scrollbar. Word PASS should appear once you drop it.</p>
+  <object type="text/html" data="helper-drop-horizontal-scrollbar.xhtml">XHTML document</object>
+  <script>
+    async function test() {
+      await new Promise(loaded => window.addEventListener("load", loaded));
+      const img = document.querySelector('img');
+      const object = document.querySelector('object');
+      const objDoc = object.contentDocument || object.contentWindow.document;
+      const div = objDoc.querySelector('div');
 
-  dragDropTest(img, object, onDropCallBack, 'Dragging the image to the horizontal object scrollbar should copy it there');
-}
-test();
-</script>
+      function onDropCallBack(event) {
+        assert_equals(div.textContent, 'PASS');
+        return true;
+      }
+
+      dragDropTest(img, div, onDropCallBack,
+        'Dragging the image to the horizontal object scrollbar should copy it there', /*dragIframe=*/ null, object);
+    }
+    test();
+  </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/024.html b/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/024.html
index 0e695cf..f2814ced6 100644
--- a/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/024.html
+++ b/third_party/blink/web_tests/external/wpt/html/editing/dnd/images/024.html
@@ -6,42 +6,51 @@
 <script src="/resources/testdriver-actions.js"></script>
 <script src="../resources/test-helper.js"></script>
 <head>
-<title>Dropping image on vertical object scrollbar</title>
-<style type="text/css">
-p:first-child
-  {padding-left:1em;}
-object
-  {height:6em;
-  width:3em;}
-img
-  {width:5px;
-  height:5px;}
-</style>
-<script type="application/ecmascript">
-function dragImage()
-  {event.dataTransfer.effectAllowed = 'copy';}
-function dropImage(event)
-  {document.querySelector('p + p').firstChild.nodeValue = 'PASS';}
-</script>
+  <title>Dropping image on vertical object scrollbar</title>
+  <style type="text/css">
+    p:first-child {
+      padding-left: 1em;
+    }
+
+    object {
+      height: 6em;
+      width: 3em;
+    }
+
+    img {
+      width: 5px;
+      height: 5px;
+    }
+  </style>
+  <script>
+    function dragImage() {
+      event.dataTransfer.effectAllowed = 'copy';
+    }
+  </script>
 </head>
 <body ondragenter="event.preventDefault()" ondragover="return false">
-<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAEElEQVR42mNgaGD4D8YwBgAw9AX9Y9zBwwAAAABJRU5ErkJggg==" alt="PNG green pixel" ondragstart="dragImage()"/></p>
-<p>Drag little square above and drop it on vertical scrollbar. Word PASS should appear once you drop it.</p>
-<object type="application/xhtml+xml" data="helper-drop-vertical-scrollbar.xhtml">XHTML document</object>
-<script>
-async function test(){
-  await new Promise(loaded => window.addEventListener("load", loaded));
-  const img = document.querySelector('img');
-  const object = document.querySelector('object');
-  function onDropCallBack(event) {
-    dropImage(event);
-    assert_equals('PASS', document.querySelector('p + p').firstChild.nodeValue);
-    return true;
-  }
+  <p><img
+      src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAEElEQVR42mNgaGD4D8YwBgAw9AX9Y9zBwwAAAABJRU5ErkJggg=="
+      alt="PNG green pixel" ondragstart="dragImage()" /></p>
+  <p>Drag little square above and drop it on vertical scrollbar. Word PASS should appear once you drop it.</p>
+  <object type="application/xhtml+xml" data="helper-drop-vertical-scrollbar.xhtml">XHTML document</object>
+  <script>
+    async function test() {
+      await new Promise(loaded => window.addEventListener("load", loaded));
+      const img = document.querySelector('img');
+      const object = document.querySelector('object');
+      const objDoc = object.contentDocument || object.contentWindow.document;
+      const div = objDoc.querySelector('div');
 
-  dragDropTest(img, object, onDropCallBack, 'Dragging the image to the vertical object scrollbar should copy it there');
-}
-test();
-</script>
+      function onDropCallBack(event) {
+        assert_equals(div.textContent, 'PASS');
+        return true;
+      }
+
+      dragDropTest(img, div, onDropCallBack,
+        'Dragging the image to the vertical object scrollbar should copy it there', /*dragIframe=*/ null, object);
+    }
+    test();
+  </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/sections-and-headings/headings-styles-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/sections-and-headings/headings-styles-expected.txt
deleted file mode 100644
index e3679df..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/sections-and-headings/headings-styles-expected.txt
+++ /dev/null
@@ -1,148 +0,0 @@
-This is a testharness.js-based test.
-Found 72 FAIL, 0 TIMEOUT, 0 NOTRUN.
-[FAIL] <h1> (in <article>) - margin-top
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <article>) - margin-bottom
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <article>) - font-size
-  assert_equals: expected "32px" but got "24px"
-[FAIL] <h1> (in <article><article>) - margin-top
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <article><article>) - margin-bottom
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <article><article>) - font-size
-  assert_equals: expected "32px" but got "18.72px"
-[FAIL] <h1> (in <article><article><article>) - margin-top
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <article><article><article>) - margin-bottom
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <article><article><article>) - font-size
-  assert_equals: expected "32px" but got "16px"
-[FAIL] <h1> (in <article><article><article><article>) - margin-top
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <article><article><article><article>) - margin-bottom
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <article><article><article><article>) - font-size
-  assert_equals: expected "32px" but got "13.28px"
-[FAIL] <h1> (in <article><article><article><article><article>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <article><article><article><article><article>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <article><article><article><article><article>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <article><article><article><article><article><hgroup>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <article><article><article><article><article><hgroup>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <article><article><article><article><article><hgroup>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <aside>) - margin-top
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <aside>) - margin-bottom
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <aside>) - font-size
-  assert_equals: expected "32px" but got "24px"
-[FAIL] <h1> (in <aside><aside>) - margin-top
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <aside><aside>) - margin-bottom
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <aside><aside>) - font-size
-  assert_equals: expected "32px" but got "18.72px"
-[FAIL] <h1> (in <aside><aside><aside>) - margin-top
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <aside><aside><aside>) - margin-bottom
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <aside><aside><aside>) - font-size
-  assert_equals: expected "32px" but got "16px"
-[FAIL] <h1> (in <aside><aside><aside><aside>) - margin-top
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <aside><aside><aside><aside>) - margin-bottom
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <aside><aside><aside><aside>) - font-size
-  assert_equals: expected "32px" but got "13.28px"
-[FAIL] <h1> (in <aside><aside><aside><aside><aside>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <aside><aside><aside><aside><aside>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <aside><aside><aside><aside><aside>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <aside><aside><aside><aside><aside><hgroup>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <aside><aside><aside><aside><aside><hgroup>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <aside><aside><aside><aside><aside><hgroup>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <nav>) - margin-top
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <nav>) - margin-bottom
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <nav>) - font-size
-  assert_equals: expected "32px" but got "24px"
-[FAIL] <h1> (in <nav><nav>) - margin-top
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <nav><nav>) - margin-bottom
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <nav><nav>) - font-size
-  assert_equals: expected "32px" but got "18.72px"
-[FAIL] <h1> (in <nav><nav><nav>) - margin-top
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <nav><nav><nav>) - margin-bottom
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <nav><nav><nav>) - font-size
-  assert_equals: expected "32px" but got "16px"
-[FAIL] <h1> (in <nav><nav><nav><nav>) - margin-top
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <nav><nav><nav><nav>) - margin-bottom
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <nav><nav><nav><nav>) - font-size
-  assert_equals: expected "32px" but got "13.28px"
-[FAIL] <h1> (in <nav><nav><nav><nav><nav>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <nav><nav><nav><nav><nav>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <nav><nav><nav><nav><nav>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <nav><nav><nav><nav><nav><hgroup>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <nav><nav><nav><nav><nav><hgroup>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <nav><nav><nav><nav><nav><hgroup>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <section>) - margin-top
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <section>) - margin-bottom
-  assert_equals: expected "21.44px" but got "19.92px"
-[FAIL] <h1> (in <section>) - font-size
-  assert_equals: expected "32px" but got "24px"
-[FAIL] <h1> (in <section><section>) - margin-top
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <section><section>) - margin-bottom
-  assert_equals: expected "21.44px" but got "18.72px"
-[FAIL] <h1> (in <section><section>) - font-size
-  assert_equals: expected "32px" but got "18.72px"
-[FAIL] <h1> (in <section><section><section>) - margin-top
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <section><section><section>) - margin-bottom
-  assert_equals: expected "21.44px" but got "21.28px"
-[FAIL] <h1> (in <section><section><section>) - font-size
-  assert_equals: expected "32px" but got "16px"
-[FAIL] <h1> (in <section><section><section><section>) - margin-top
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <section><section><section><section>) - margin-bottom
-  assert_equals: expected "21.44px" but got "22.1776px"
-[FAIL] <h1> (in <section><section><section><section>) - font-size
-  assert_equals: expected "32px" but got "13.28px"
-[FAIL] <h1> (in <section><section><section><section><section>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <section><section><section><section><section>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <section><section><section><section><section>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-[FAIL] <h1> (in <section><section><section><section><section><hgroup>) - margin-top
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <section><section><section><section><section><hgroup>) - margin-bottom
-  assert_equals: expected "21.44px" but got "24.9776px"
-[FAIL] <h1> (in <section><section><section><section><section><hgroup>) - font-size
-  assert_equals: expected "32px" but got "10.72px"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/canvas-background.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/canvas-background.html.ini
index 198b67c4..8e79877c 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/canvas-background.html.ini
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/assumptions/canvas-background.html.ini
@@ -1,3 +1,3 @@
 [canvas-background.html]
   expected:
-    if product == "safari": [ERROR, CRASH]
+    if product == "safari": [ERROR, PASS]
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini
index 74470b82..d9a0e763 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/server/http2-websocket.sub.h2.any.js.ini
@@ -1,16 +1,12 @@
 [http2-websocket.sub.h2.any.html]
-  expected:
-    if product == "safari": TIMEOUT
   [WSS over h2]
     expected:
       if product == "epiphany" or product == "webkit": FAIL
-      if product == "safari": TIMEOUT
+      if product == "safari": FAIL
 
 
 [http2-websocket.sub.h2.any.worker.html]
-  expected:
-    if product == "safari": TIMEOUT
   [WSS over h2]
     expected:
       if product == "epiphany" or product == "webkit": FAIL
-      if product == "safari": TIMEOUT
+      if product == "safari": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini
index ce88c72..8b7c0f25 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/testdriver/file_upload.sub.html.ini
@@ -5,4 +5,3 @@
     expected:
       if (product == "epiphany") or (product == "webkit"): FAIL
       if product == "firefox_android": FAIL
-      if product == "safari": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/window/minimize-1.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/window/minimize-1.html.ini
index 2e3ac519..5566efc7 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/window/minimize-1.html.ini
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/window/minimize-1.html.ini
@@ -2,3 +2,4 @@
   [Minimize a window]
     expected:
       if os == "android": FAIL
+      if product == "safari": [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-expected.txt b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-expected.txt
new file mode 100644
index 0000000..bd90b52
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+[FAIL] LCP should be updated if the web font styled text resizes to be larger during the swap period
+  assert_equals: There should be 2 LCP entries. The 1st one corresponds to the system font and the 2nd the web font. expected 2 but got 1
+Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode-expected.txt b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode-expected.txt
new file mode 100644
index 0000000..149db54d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+[FAIL] LCP should be updated if the web font styled text resizes to be larger during the swap period
+  assert_equals: There should be 2 LCP entries. The 1st one corresponds to the system font and the 2nd the web font. expected 2 but got 1
+Harness: the test ran to completion.
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode.html
index eca5f35..bd368d66 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode.html
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap-subnode.html
@@ -1,17 +1,16 @@
-<!DOCTYPE html>
+<!doctype html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
   @font-face {
-    font-family: 'ADTestFaceSwapSubnode';
-    src: url('/fonts/AD.woff?pipe=trickle(d0.5)');
+    font-family: "ADTestFaceSwapSubnode";
+    src: url("/fonts/AD.woff?pipe=trickle(d0.5)");
     font-display: swap;
   }
 
   .test {
-    font-family: 'ADTestFaceSwapSubnode';
+    font-family: "ADTestFaceSwapSubnode";
   }
-
 </style>
 <!--
   Web-font styled subnode text that gets resized during swap period should make
@@ -21,39 +20,55 @@
   <span>LCP: Web Font Styled Text Resize</span>
 </div>
 <script>
-                        function LCPEntryList() {
-    return new Promise(resolve => {
-      let = lcpEntries = [];
-      new PerformanceObserver((entryList, observer) => {
-        lcpEntries = lcpEntries.concat(entryList.getEntries());
-        if (lcpEntries.length == 2) {
-          resolve(lcpEntries);
-          observer.disconnect();
-        }
-      }).observe({ type: 'largest-contentful-paint', buffered: true });
-    });
-  }
-
-  promise_test(async t => {
+  promise_test(async (t) => {
     await document.fonts.ready;
 
     // Verify web font is downloaded.
-    assert_own_property(window, 'PerformanceResourceTiming', "ResourceTiming not supported");
-    let url = '/fonts/AD.woff?pipe=trickle(d0.5)';
+    assert_own_property(window, "PerformanceResourceTiming", "ResourceTiming not supported");
+    let url = "/fonts/AD.woff?pipe=trickle(d0.5)";
     var absoluteURL = new URL(url, location.href).href;
-    assert_equals(performance.getEntriesByName(absoluteURL).length, 1, 'Web font\
-    should be downloaded');
+    assert_equals(
+      performance.getEntriesByName(absoluteURL).length,
+      1,
+      "Web font should be downloaded",
+    );
 
     // Verify web font is available.
-    assert_true(document.fonts.check('16px ADTestFaceSwapSubnode'), 'Font should be the web font added');
+    assert_true(
+      document.fonts.check("16px ADTestFaceSwapSubnode"),
+      "Font should be the web font added",
+    );
 
-    let entryList = await LCPEntryList();
+    let lcpEntries = [];
+    await Promise.race([
+      new Promise((resolve, reject) => {
+        t.step_timeout(() => {
+          resolve(lcpEntries);
+        }, 3000);
+      }),
+      new Promise((resolve, reject) => {
+        new PerformanceObserver((list, observer) => {
+          lcpEntries.push(...list.getEntries());
+          if (lcpEntries.length >= 2) {
+            resolve();
+            observer.disconnect();
+          }
+        }).observe({ type: "largest-contentful-paint", buffered: true });
+      }),
+    ]);
 
     // Verify there are 2 LCP entries emitted.
-    assert_equals(entryList.length, 2, 'There should be 2 LCP entries. The 1st one corresponds to the system font and the 2nd the web font.')
+    assert_equals(
+      lcpEntries.length,
+      2,
+      "There should be 2 LCP entries. The 1st one corresponds to the system font and the 2nd the web font.",
+    );
 
     // Verify the size of 2nd LCP entry is larger than that of the 1st one.
-    assert_greater_than(entryList[1].size, entryList[0].size, 'The size of 2nd LCP entry should be larger than that of the 1st one.');
-
+    assert_greater_than(
+      lcpEntries[1].size,
+      lcpEntries[0].size,
+      "The size of 2nd LCP entry should be larger than that of the 1st one.",
+    );
   }, "LCP should be updated if the web font styled text resizes to be larger during the swap period");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap.html
index 61c00fad..a2250e8d 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap.html
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/web-font-styled-text-resize-swap.html
@@ -1,17 +1,16 @@
-<!DOCTYPE html>
+<!doctype html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
   @font-face {
-    font-family: 'ADTestFaceSwap';
-    src: url('/fonts/AD.woff?pipe=trickle(d0.5)');
+    font-family: "ADTestFaceSwap";
+    src: url("/fonts/AD.woff?pipe=trickle(d0.5)");
     font-display: swap;
   }
 
   .test {
-    font-family: 'ADTestFaceSwap';
+    font-family: "ADTestFaceSwap";
   }
-
 </style>
 <!--
   Web-font styled text that gets resized during swap period should make a
@@ -19,39 +18,52 @@
 -->
 <div class="test">LCP: Web Font Styled Text Resize</div>
 <script>
-  function LCPEntryList() {
-    return new Promise(resolve => {
-      let = lcpEntries = [];
-      new PerformanceObserver((entryList, observer) => {
-        lcpEntries = lcpEntries.concat(entryList.getEntries());
-        if (lcpEntries.length == 2) {
-          resolve(lcpEntries);
-          observer.disconnect();
-        }
-      }).observe({ type: 'largest-contentful-paint', buffered: true });
-    });
-  }
-
-  promise_test(async t => {
+  promise_test(async (t) => {
     await document.fonts.ready;
 
     // Verify web font is downloaded.
-    assert_own_property(window, 'PerformanceResourceTiming', "ResourceTiming not supported");
-    let url = '/fonts/AD.woff?pipe=trickle(d0.5)';
+    assert_own_property(window, "PerformanceResourceTiming", "ResourceTiming not supported");
+    let url = "/fonts/AD.woff?pipe=trickle(d0.5)";
     var absoluteURL = new URL(url, location.href).href;
-    assert_equals(performance.getEntriesByName(absoluteURL).length, 1, 'Web font\
-    should be downloaded');
+    assert_equals(
+      performance.getEntriesByName(absoluteURL).length,
+      1,
+      "Web font should be downloaded",
+    );
 
     // Verify web font is available.
-    assert_true(document.fonts.check('16px ADTestFaceSwap'), 'Font should be the web font added');
+    assert_true(document.fonts.check("16px ADTestFaceSwap"), "Font should be the web font added");
 
-    let entryList = await LCPEntryList();
+    let lcpEntries = [];
+    await Promise.race([
+      new Promise((resolve, reject) => {
+        t.step_timeout(() => {
+          resolve(lcpEntries);
+        }, 3000);
+      }),
+      new Promise((resolve, reject) => {
+        new PerformanceObserver((list, observer) => {
+          lcpEntries.push(...list.getEntries());
+          if (lcpEntries.length >= 2) {
+            resolve();
+            observer.disconnect();
+          }
+        }).observe({ type: "largest-contentful-paint", buffered: true });
+      }),
+    ]);
 
     // Verify there are 2 LCP entries emitted.
-    assert_equals(entryList.length, 2, 'There should be 2 LCP entries. The 1st one corresponds to the system font and the 2nd the web font.')
+    assert_equals(
+      lcpEntries.length,
+      2,
+      "There should be 2 LCP entries. The 1st one corresponds to the system font and the 2nd the web font.",
+    );
 
     // Verify the size of 2nd LCP entry is larger than that of the 1st one.
-    assert_greater_than(entryList[1].size, entryList[0].size, 'The size of 2ndLCP entry should be larger than that of the 1st one.');
-
-  }, "LCP should be updated if the web font styled text resizes to be larger   during the swap period");
+    assert_greater_than(
+      lcpEntries[1].size,
+      lcpEntries[0].size,
+      "The size of 2ndLCP entry should be larger than that of the 1st one.",
+    );
+  }, "LCP should be updated if the web font styled text resizes to be larger during the swap period");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/selection/crashtests/selectall-and-find-svg-text-on-selectstart.html b/third_party/blink/web_tests/external/wpt/selection/crashtests/selectall-and-find-svg-text-on-selectstart.html
index 9f9dfbc..b49dee2 100644
--- a/third_party/blink/web_tests/external/wpt/selection/crashtests/selectall-and-find-svg-text-on-selectstart.html
+++ b/third_party/blink/web_tests/external/wpt/selection/crashtests/selectall-and-find-svg-text-on-selectstart.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <head>
 <meta charset="utf-8">
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-clip-crash.html b/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-clip-crash.html
index 66d10b4..4179356 100644
--- a/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-clip-crash.html
+++ b/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-clip-crash.html
@@ -2,7 +2,7 @@
 <meta charset="utf-8">
 <link rel="author" title="Philip Rogers" href="mailto:pdr@chromium.org">
 <meta name="assert" content="Moving a selection to a different clipper should not crash">
-<html class=reftest-wait>
+<html class=test-wait>
   <script>
     function test() {
       document.designMode = "on";
@@ -19,7 +19,7 @@
           updated_range.setStart(b, 1);
           updated_range.setEnd(b, 1);
 
-          document.documentElement.classList.remove("reftest-wait");
+          document.documentElement.classList.remove("test-wait");
         });
       });
     }
diff --git a/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-shadow.html b/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-shadow.html
index bfca040..13faa4ed 100644
--- a/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-shadow.html
+++ b/third_party/blink/web_tests/external/wpt/selection/crashtests/selection-modify-line-boundary-around-shadow.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html class="reftest-wait">
+<html class="test-wait">
 <head>
 <meta charset="utf-8">
 <script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-001-crash.html b/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-001-crash.html
index bd38d93..96821bd 100644
--- a/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-001-crash.html
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-001-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <title>Seeking the time container to a large value does not cause a crash (or hang)</title>
 <svg>
   <rect height="100" width="100" fill="blue">
@@ -11,5 +11,5 @@
   let svg = document.querySelector("svg");
   svg.setCurrentTime(18446744073709551557);
   let html = document.documentElement;
-  html.addEventListener("TestRendered", () => html.classList.remove("reftest-wait"));
+  html.addEventListener("TestRendered", () => html.classList.remove("test-wait"));
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-002-crash.html b/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-002-crash.html
index 6951820f..58fbf98 100644
--- a/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-002-crash.html
+++ b/third_party/blink/web_tests/external/wpt/svg/animations/end-of-time-002-crash.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html class="reftest-wait">
+<html class="test-wait">
 <title>Seeking the time container to a large value does not cause a crash (or hang)</title>
 <svg>
   <rect height="100" width="100" fill="blue">
@@ -11,5 +11,5 @@
   let svg = document.querySelector("svg");
   svg.setCurrentTime(9000000000000000);
   let html = document.documentElement;
-  html.addEventListener("TestRendered", () => html.classList.remove("reftest-wait"));
+  html.addEventListener("TestRendered", () => html.classList.remove("test-wait"));
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/resources/audit-util.js b/third_party/blink/web_tests/external/wpt/webaudio/resources/audit-util.js
index e036445..544bd20 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/resources/audit-util.js
+++ b/third_party/blink/web_tests/external/wpt/webaudio/resources/audit-util.js
@@ -278,13 +278,40 @@
  */
 function assert_array_approximately_equals(
     actual, expected, threshold, message) {
-      assert_equals(
-          actual.length,
-          expected.length,
-          `${message} - buffer lengths must match`);
-      for (let i = 0; i < actual.length; ++i) {
-        assert_approx_equals(
-            actual[i], expected[i], threshold,
-            `${message} at index ${i}`);
-      }
+  assert_equals(
+      actual.length,
+      expected.length,
+      `${message} - buffer lengths must match`);
+  for (let i = 0; i < actual.length; ++i) {
+    assert_approx_equals(
+        actual[i], expected[i], threshold,
+        `${message} at index ${i}`);
+  }
+}
+
+/**
+ * Asserts that two arrays are of equal length and that each corresponding
+ * element is within a specified epsilon of each other. Throws an assertion
+ * error if any element pair differs by more than epsilon or if the arrays
+ * have different lengths.
+ *
+ * @param {Array<number>} actual - The array of actual values to test.
+ * @param {Array<number>} expected - The array of expected values to compare
+ *   against.
+ * @param {number} epsilon - The maximum allowed difference between
+ *   corresponding elements.
+ * @param {string} desc - Description used in assertion error messages.
+ */
+function assert_close_to_array(actual, expected, epsilon, desc) {
+  assert_equals(
+      actual.length,
+      expected.length,
+      `${desc}: length mismatch`);
+  for (let i = 0; i < actual.length; ++i) {
+    const diff = Math.abs(actual[i] - expected[i]);
+    assert_less_than_equal(
+        diff,
+        epsilon,
+        `${desc}[${i}] |${actual[i]} - ${expected[i]}| = ${diff} > ${epsilon}`);
+  }
 }
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html
index 954c71a..9cb2ab5 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-channelsplitternode-interface/audiochannelsplitter.html
@@ -1,141 +1,107 @@
 <!DOCTYPE html>
-<!--
-Tests that AudioChannelSplitter works correctly.
--->
 <html>
   <head>
     <title>
-      audiochannelsplitter.html
+      Tests AudioChannelSplitter
     </title>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="/webaudio/resources/audit-util.js"></script>
-    <script src="/webaudio/resources/audit.js"></script>
   </head>
   <body>
-    <script id="layout-test-code">
-      let audit = Audit.createTaskRunner();
+    <script>
 
-      let sampleRate = 44100.0;
-      let lengthInSampleFrames = 512;
+      // Arbitrary power-of-two-length render so timing math is exact.
+      const sampleRate = 44100.0;
+      const lengthInSampleFrames = 512;
 
-      let context = 0;
-      let sourceBuffer;
-      let sourceNode;
-      let channelSplitter;
-      let channelMerger;
+      // checkResult() checks that the rendered buffer is stereo and that the
+      // left channel is all –1 and right channel all +1. In other words,
+      // we've reversed the order of the two channels.
+      function checkResult(buffer) {
+        assert_equals(
+            buffer.numberOfChannels,
+            2,
+            'Rendered buffer must be stereo');
 
-      function createStereoBufferWithDCOffset(length, sampleRate, offset) {
-        let buffer = context.createBuffer(2, length, sampleRate);
-        let n = buffer.length;
-        let channelL = buffer.getChannelData(0);
-        let channelR = buffer.getChannelData(1);
+        const left = buffer.getChannelData(0);
+        const right = buffer.getChannelData(1);
 
-        for (let i = 0; i < n; ++i) {
+        assert_constant_value(left, -1, 'Left channel:');
+        assert_constant_value(right, 1, 'Right channel:');
+      }
+
+      function createStereoBufferWithDCOffset(context, length, sr, offset) {
+        const buffer = new AudioBuffer({
+          numberOfChannels: 2,
+          length: length,
+          sampleRate: sr
+        });
+        const channelL = buffer.getChannelData(0);
+        const channelR = buffer.getChannelData(1);
+
+        for (let i = 0; i < length; ++i) {
           channelL[i] = offset;
-          channelR[i] = -1.0 * offset;
+          channelR[i] = -offset;
         }
-
         return buffer;
       }
 
-      // checkResult() checks that the rendered buffer is stereo and that the
-      // left channel is all -1 and right channel all +1. In other words, we've
-      // reversed the order of the two channels.
-      function checkResult(buffer, should) {
-        let success = true;
+      test(t => {
+        // Create a stereo OfflineAudioContext.
+        const context = new OfflineAudioContext(
+            2, lengthInSampleFrames, sampleRate);
 
-        if (buffer.numberOfChannels == 2) {
-          let bufferDataL = buffer.getChannelData(0);
-          let bufferDataR = buffer.getChannelData(1);
+        // Invalid splitter channel counts.
+        assert_throws_dom('IndexSizeError',
+                          () => context.createChannelSplitter(0),
+                          'createChannelSplitter(0) must throw');
+        assert_throws_dom('IndexSizeError',
+                          () => context.createChannelSplitter(33),
+                          'createChannelSplitter(33) must throw');
 
-          success = should(bufferDataL, 'Left channel').beConstantValueOf(-1) &&
-              success;
-          success = should(bufferDataR, 'Right channel').beConstantValueOf(1) &&
-              success;
-        } else {
-          success = false;
-        }
+        // Maximum valid splitter.
+        let splitter = context.createChannelSplitter(32);
+        assert_equals(splitter.numberOfOutputs, 32,
+                      'splitter.numberOfOutputs');
+        assert_equals(splitter.numberOfInputs, 1,
+                      'splitter.numberOfInputs');
 
-        should(success, 'Left and right channels were exchanged')
-            .message('correctly', 'incorrectly');
-      }
+        // Default constructor should yield 6 outputs.
+        splitter = context.createChannelSplitter();
+        assert_equals(splitter.numberOfOutputs, 6,
+                      'Default output count should be 6');
+      }, 'Construction of ChannelSplitterNode');
 
-      audit.define(
-          {
-            label: 'construction',
-            description: 'Construction of ChannelSplitterNode'
-          },
-          function(task, should) {
 
-            // Create stereo offline audio context.
-            context =
-                new OfflineAudioContext(2, lengthInSampleFrames, sampleRate);
+      promise_test(async t => {
+        // Create a stereo OfflineAudioContext.
+        const context = new OfflineAudioContext(
+            2, lengthInSampleFrames, sampleRate);
 
-            let splitternode;
-            should(() => {
-              let splitternode = context.createChannelSplitter(0);
-            }, 'createChannelSplitter(0)').throw(DOMException, 'IndexSizeError');
+        // Create a stereo buffer, with all +1 values in left channel, all
+        // –1 in right channel.
+        const srcBuffer = createStereoBufferWithDCOffset(
+            context, lengthInSampleFrames, sampleRate, 1);
 
-            should(() => {
-              splitternode = context.createChannelSplitter(33);
-            }, 'createChannelSplitter(33)').throw(DOMException, 'IndexSizeError');
+        const source = new AudioBufferSourceNode(context, {
+          buffer: srcBuffer
+        });
+        const splitter = new ChannelSplitterNode(context, {
+          numberOfOutputs: 2
+        });
+        const merger = new ChannelMergerNode(context);
 
-            should(() => {
-              splitternode = context.createChannelSplitter(32);
-            }, 'splitternode = context.createChannelSplitter(32)').notThrow();
+        source.connect(splitter);
+        splitter.connect(merger, 0, 1);
+        splitter.connect(merger, 1, 0);
+        merger.connect(context.destination);
 
-            should(splitternode.numberOfOutputs, 'splitternode.numberOfOutputs')
-                .beEqualTo(32);
-            should(splitternode.numberOfInputs, 'splitternode.numberOfInputs')
-                .beEqualTo(1)
+        source.start();
 
-            should(() => {
-              splitternode = context.createChannelSplitter();
-            }, 'splitternode = context.createChannelSplitter()').notThrow();
-
-            should(splitternode.numberOfOutputs, 'splitternode.numberOfOutputs')
-                .beEqualTo(6);
-
-            task.done();
-          });
-
-      audit.define(
-          {
-            label: 'functionality',
-            description: 'Functionality of ChannelSplitterNode'
-          },
-          function(task, should) {
-
-            // Create a stereo buffer, with all +1 values in left channel, all
-            // -1 in right channel.
-            sourceBuffer = createStereoBufferWithDCOffset(
-                lengthInSampleFrames, sampleRate, 1);
-
-            sourceNode = context.createBufferSource();
-            sourceNode.buffer = sourceBuffer;
-
-            // Create a channel splitter and connect it so that it split the
-            // stereo stream into two mono streams.
-            channelSplitter = context.createChannelSplitter(2);
-            sourceNode.connect(channelSplitter);
-
-            // Create a channel merger to merge the output of channel splitter.
-            channelMerger = context.createChannelMerger();
-            channelMerger.connect(context.destination);
-
-            // When merging, exchange channel layout: left->right, right->left
-            channelSplitter.connect(channelMerger, 0, 1);
-            channelSplitter.connect(channelMerger, 1, 0);
-
-            sourceNode.start(0);
-
-            context.startRendering()
-                .then(buffer => checkResult(buffer, should))
-                .then(task.done.bind(task));
-          });
-
-      audit.run();
+        const renderedBuffer = await context.startRendering();
+        checkResult(renderedBuffer);
+      }, 'Functionality of ChannelSplitterNode (channel swap)');
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html
index c98555f..eeb4af3 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html
@@ -7,20 +7,17 @@
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script src="../../resources/audit-util.js"></script>
-    <script src="../../resources/audit.js"></script>
     <script src="../../resources/biquad-filters.js"></script>
   </head>
   <body>
-    <script id="layout-test-code">
-      let sampleRate = 48000;
+    <script>
+
+      const sampleRate = 48000;
       // Some short duration; we're not actually looking at the rendered output.
-      let testDurationSec = 0.01;
+      const testDurationSec = 0.01;
 
       // Number of frequency samples to take.
-      let numberOfFrequencies = 1000;
-
-      let audit = Audit.createTaskRunner();
-
+      const numberOfFrequencies = 1000;
 
       // Compute a set of linearly spaced frequencies.
       function createFrequencies(nFrequencies, sampleRate) {
@@ -35,18 +32,17 @@
         return frequencies;
       }
 
-      audit.define('1-pole IIR', (task, should) => {
-        let context = new OfflineAudioContext(
+      test(t => {
+        const context = new OfflineAudioContext(
             1, testDurationSec * sampleRate, sampleRate);
+        const iir = context.createIIRFilter([1], [1, -0.9]);
 
-        let iir = context.createIIRFilter([1], [1, -0.9]);
-        let frequencies =
-            createFrequencies(numberOfFrequencies, context.sampleRate);
-
-        let iirMag = new Float32Array(numberOfFrequencies);
-        let iirPhase = new Float32Array(numberOfFrequencies);
-        let trueMag = new Float32Array(numberOfFrequencies);
-        let truePhase = new Float32Array(numberOfFrequencies);
+        const frequencies = createFrequencies(
+            numberOfFrequencies, context.sampleRate);
+        const iirMag = new Float32Array(numberOfFrequencies);
+        const iirPhase = new Float32Array(numberOfFrequencies);
+        const trueMag = new Float32Array(numberOfFrequencies);
+        const truePhase = new Float32Array(numberOfFrequencies);
 
         // The IIR filter is
         //   H(z) = 1/(1 - 0.9*z^(-1)).
@@ -60,10 +56,9 @@
         // The phase is
         //   arg(H(exp(j*w)) = atan(0.9*sin(w)/(.9*cos(w)-1))
 
-        let frequencyScale = Math.PI / (sampleRate / 2);
-
+        const frequencyScale = Math.PI / (sampleRate / 2);
         for (let k = 0; k < frequencies.length; ++k) {
-          let omega = frequencyScale * frequencies[k];
+          const omega = frequencyScale * frequencies[k];
           trueMag[k] = 1 / Math.sqrt(1.81 - 1.8 * Math.cos(omega));
           truePhase[k] =
               Math.atan(0.9 * Math.sin(omega) / (0.9 * Math.cos(omega) - 1));
@@ -72,88 +67,71 @@
         iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
 
         // Thresholds were experimentally determined.
-        should(iirMag, '1-pole IIR Magnitude Response')
-            .beCloseToArray(trueMag, {absoluteThreshold: 2.8611e-6});
-        should(iirPhase, '1-pole IIR Phase Response')
-            .beCloseToArray(truePhase, {absoluteThreshold: 1.7882e-7});
+        assert_close_to_array(
+            iirMag, trueMag, 2.8611e-6, '1‑pole IIR magnitude response ' +
+            'should be closed to calculated magnitude response');
+        assert_close_to_array(
+            iirPhase, truePhase, 1.7882e-7, '1‑pole IIR phase response ' +
+            ' should be closed to calculated phase response');
+      }, '1‑pole IIR getFrequencyResponse() matches analytic response');
 
-        task.done();
-      });
-
-      audit.define('compare IIR and biquad', (task, should) => {
+      test(t => {
         // Create an IIR filter equivalent to the biquad filter. Compute the
         // frequency response for both and verify that they are the same.
-        let context = new OfflineAudioContext(
+        const context = new OfflineAudioContext(
             1, testDurationSec * sampleRate, sampleRate);
 
-        let biquad = context.createBiquadFilter();
-        let coef = createFilter(
-            biquad.type, biquad.frequency.value / (context.sampleRate / 2),
-            biquad.Q.value, biquad.gain.value);
+        const biquad = context.createBiquadFilter();
+        const coef = createFilter(
+          biquad.type,
+          biquad.frequency.value / (context.sampleRate / 2),
+          biquad.Q.value,
+          biquad.gain.value);
 
-        let iir = context.createIIRFilter(
+        const iir = context.createIIRFilter(
             [coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
 
-        let frequencies =
-            createFrequencies(numberOfFrequencies, context.sampleRate);
-        let biquadMag = new Float32Array(numberOfFrequencies);
-        let biquadPhase = new Float32Array(numberOfFrequencies);
-        let iirMag = new Float32Array(numberOfFrequencies);
-        let iirPhase = new Float32Array(numberOfFrequencies);
+        const frequencies = createFrequencies(
+            numberOfFrequencies, context.sampleRate);
+        const biquadMag = new Float32Array(numberOfFrequencies);
+        const biquadPhase = new Float32Array(numberOfFrequencies);
+        const iirMag = new Float32Array(numberOfFrequencies);
+        const iirPhase = new Float32Array(numberOfFrequencies);
 
         biquad.getFrequencyResponse(frequencies, biquadMag, biquadPhase);
         iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
+      // Thresholds were experimentally determined.
+        assert_close_to_array(
+            iirMag, biquadMag, 2.7419e-5, 'IIR magnitude response should be' +
+            'close to Biquad magnitude response');
+        assert_close_to_array(
+            iirPhase, biquadPhase, 2.7657e-5, 'IIR phase response should be' +
+            'close to Biquad phase response');
+      }, 'IIR filter equivalent to biquad has matching frequency response');
 
-        // Thresholds were experimentally determined.
-        should(iirMag, 'IIR Magnitude Response').beCloseToArray(biquadMag, {
-          absoluteThreshold: 2.7419e-5
-        });
-        should(iirPhase, 'IIR Phase Response').beCloseToArray(biquadPhase, {
-          absoluteThreshold: 2.7657e-5
-        });
+      test(t => {
+        const context = new OfflineAudioContext(1, 1, sampleRate);
+        const filter = new IIRFilterNode(
+            context, {feedforward: [1], feedback: [1, -0.9]});
+        // Frequencies to test.  These are all outside the valid range of
+        // frequencies of 0 to Nyquist.
+        const freq = new Float32Array([-1, context.sampleRate / 2 + 1]);
+        const mag = new Float32Array(freq.length);
+        const phase = new Float32Array(freq.length);
 
-        task.done();
-      });
+        filter.getFrequencyResponse(freq, mag, phase);
 
-      audit.define(
-          {
-            label: 'getFrequencyResponse',
-            description: 'Test out-of-bounds frequency values'
-          },
-          (task, should) => {
-            let context = new OfflineAudioContext(1, 1, sampleRate);
-            let filter = new IIRFilterNode(
-                context, {feedforward: [1], feedback: [1, -.9]});
-
-            // Frequencies to test.  These are all outside the valid range of
-            // frequencies of 0 to Nyquist.
-            let freq = new Float32Array(2);
-            freq[0] = -1;
-            freq[1] = context.sampleRate / 2 + 1;
-
-            let mag = new Float32Array(freq.length);
-            let phase = new Float32Array(freq.length);
-
-            filter.getFrequencyResponse(freq, mag, phase);
-
-            // Verify that the returned magnitude and phase entries are alL NaN
-            // since the frequencies are outside the valid range
-            for (let k = 0; k < mag.length; ++k) {
-              should(mag[k],
-                  'Magnitude response at frequency ' + freq[k])
-                  .beNaN();
-            }
-
-            for (let k = 0; k < phase.length; ++k) {
-              should(phase[k],
-                  'Phase response at frequency ' + freq[k])
-                  .beNaN();
-            }
-
-            task.done();
-          });
-
-      audit.run();
+        // Verify that the returned magnitude and phase entries are all NaN
+        // since the frequencies are outside the valid range
+        for (let k = 0; k < freq.length; ++k) {
+          assert_true(
+              Number.isNaN(mag[k]),
+              `Magnitude response at f=${freq[k]} should be NaN`);
+          assert_true(
+              Number.isNaN(phase[k]),
+              `Phase response at f=${freq[k]} should be NaN`);
+        }
+      }, 'Out‑of‑range frequency values yield NaN responses');
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/setter-argument-expected.txt b/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/setter-argument-expected.txt
new file mode 100644
index 0000000..023b960
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/setter-argument-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+[FAIL] Object attribute setter should treat no arguments as undefined
+  assert_throws_dom: function "() => { setter.call(thisValue); }" threw object "TypeError: Failed to set the 'body' property on 'Document': 1 argument required, but only 0 present." that is not a DOMException HierarchyRequestError: property "code" is equal to undefined, expected 3
+[FAIL] [Replaceable] setter should treat no arguments as undefined
+  Failed to set the 'scrollX' property on 'Window': 1 argument required, but only 0 present.
+[FAIL] [PutForward] setter should treat no arguments as undefined
+  Failed to set the 'relList' property on 'HTMLAnchorElement': 1 argument required, but only 0 present.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/setter-argument.html b/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/setter-argument.html
new file mode 100644
index 0000000..bfa4291
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/setter-argument.html
@@ -0,0 +1,176 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Setter should treat no arguments as undefined</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const invalidThisValues = [undefined, null, 1, {}, new Image()];
+
+// String attribute.
+
+test(() => {
+  const setter = Object.getOwnPropertyDescriptor(Animation.prototype, "id").set;
+
+  for (const thisValue of invalidThisValues) {
+    assert_throws_js(TypeError, () => { setter.call(thisValue); });
+    assert_throws_js(TypeError, () => { setter.call(thisValue, undefined); });
+    assert_throws_js(TypeError, () => { setter.call(thisValue, "foo"); });
+  }
+}, `String attribute setter should throw if this value is invalid`);
+
+test(() => {
+  const thisValue = new Animation();
+  const setter = Object.getOwnPropertyDescriptor(Animation.prototype, "id").set;
+
+  assert_equals(thisValue.id, "");
+
+  setter.call(thisValue);
+  assert_equals(thisValue.id, "undefined",
+               "undefined value should be stringified");
+}, `String attribute setter should treat no arguments as undefined`);
+
+test(() => {
+  const thisValue = new Animation();
+  const setter = Object.getOwnPropertyDescriptor(Animation.prototype, "id").set;
+
+  assert_equals(thisValue.id, "");
+
+  setter.call(thisValue, undefined);
+  assert_equals(thisValue.id, "undefined",
+               "undefined value should be stringified");
+}, `String attribute setter called with undefined should behave in the same way as no arguments`);
+
+test(() => {
+  const thisValue = new Animation();
+  const setter = Object.getOwnPropertyDescriptor(Animation.prototype, "id").set;
+
+  assert_equals(thisValue.id, "");
+
+  setter.call(thisValue, "foo");
+  assert_equals(thisValue.id, "foo");
+}, `String attribute setter called with string should just work`);
+
+// Object attribute.
+
+test(() => {
+  const setter = Object.getOwnPropertyDescriptor(Document.prototype, "body").set;
+
+  for (const thisValue of invalidThisValues) {
+    assert_throws_js(TypeError, () => { setter.call(thisValue); });
+    assert_throws_js(TypeError, () => { setter.call(thisValue, undefined); });
+    assert_throws_js(TypeError, () => { setter.call(thisValue, "foo"); });
+  }
+}, `Object attribute setter should throw if this value is invalid`);
+
+test(() => {
+  const thisValue = new Document();
+  const setter = Object.getOwnPropertyDescriptor(Document.prototype, "body").set;
+
+  assert_throws_dom("HierarchyRequestError", () => { setter.call(thisValue); });
+}, `Object attribute setter should treat no arguments as undefined`);
+
+test(() => {
+  const thisValue = new Document();
+  const setter = Object.getOwnPropertyDescriptor(Document.prototype, "body").set;
+
+  assert_throws_dom("HierarchyRequestError", () => { setter.call(thisValue, undefined); });
+}, `Object attribute setter called with undefined should behave in the same way as no arguments`);
+
+// [Replaceable] attribute.
+
+test(() => {
+  const thisValue = window;
+  const setter = Object.getOwnPropertyDescriptor(window, "scrollX").set;
+
+  setter.call(thisValue);
+  assert_equals(thisValue.scrollX, undefined);
+}, `[Replaceable] setter should treat no arguments as undefined`);
+
+test(() => {
+  const thisValue = window;
+  const setter = Object.getOwnPropertyDescriptor(window, "screenLeft").set;
+
+  setter.call(thisValue, undefined);
+  assert_equals(thisValue.screenLeft, undefined);
+}, `[Replaceable] setter called with undefined should behave in the same way as no arguments`);
+
+test(() => {
+  const thisValue = window;
+  const setter = Object.getOwnPropertyDescriptor(window, "screenTop").set;
+
+  setter.call(thisValue, "foo");
+  assert_equals(thisValue.screenTop, "foo");
+}, `[Replaceable] setter called with other value should just work`);
+
+// [LegacyLenientThis] attribute.
+
+test(() => {
+  const setter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "onmouseenter").set;
+
+  for (const thisValue of invalidThisValues) {
+    setter.call(thisValue);
+    setter.call(thisValue, undefined);
+    setter.call(thisValue, "foo");
+  }
+}, `[LegacyLenientThis] setter should not throw even if this value is invalid, regardless of the arguments count`);
+
+test(() => {
+  const thisValue = document.createElement("div");
+  const setter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "onmouseenter").set;
+
+  setter.call(thisValue);
+  assert_equals(thisValue.onmouseenter, null);
+}, `[LegacyLenientThis] setter should treat no arguments as undefined`);
+
+test(() => {
+  const thisValue = document.createElement("div");
+  const setter = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "onmouseenter").set;
+
+  setter.call(thisValue, undefined);
+  assert_equals(thisValue.onmouseenter, null);
+}, `[LegacyLenientThis] setter called with undefined should behave in the same way as no arguments`);
+
+// [LegacyLenientSetter] attribute.
+
+test(() => {
+  const thisValue = new Document();
+  const setter = Object.getOwnPropertyDescriptor(Document.prototype, "fullscreenEnabled").set;
+
+  setter.call(thisValue);
+  assert_equals(thisValue.fullscreenEnabled, false);
+}, `[LegacyLenientSetter] setter should treat no arguments as undefined`);
+
+test(() => {
+  const thisValue = new Document();
+  const setter = Object.getOwnPropertyDescriptor(Document.prototype, "fullscreenEnabled").set;
+
+  setter.call(thisValue, undefined);
+  assert_equals(thisValue.fullscreenEnabled, false);
+}, `[LegacyLenientSetter] setter called with undefined should behave in the same way as no arguments`);
+
+// [PutForward] attribute.
+
+test(() => {
+  const thisValue = document.createElement("a");
+  const setter = Object.getOwnPropertyDescriptor(HTMLAnchorElement.prototype, "relList").set;
+
+  assert_equals(thisValue.relList.length, 0);
+
+  setter.call(thisValue);
+  assert_equals(thisValue.relList.length, 1);
+  assert_equals(thisValue.relList[0], "undefined");
+}, `[PutForward] setter should treat no arguments as undefined`);
+
+test(() => {
+  const thisValue = document.createElement("a");
+  const setter = Object.getOwnPropertyDescriptor(HTMLAnchorElement.prototype, "relList").set;
+
+  assert_equals(thisValue.relList.length, 0);
+
+  setter.call(thisValue, undefined);
+
+  assert_equals(thisValue.relList.length, 1);
+  assert_equals(thisValue.relList[0], "undefined");
+}, `[PutForward] setter called with undefined should behave in the same way as no arguments`);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/abs.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/abs.https.any.js
index ea4370c..20e260b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/abs.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/abs.https.any.js
@@ -623,7 +623,7 @@
 ];
 
 if (navigator.ml) {
-  absTests.forEach((test) => {
+  absTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getAbsPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/add.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/add.https.any.js
index 5a370de..8fa8176f 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/add.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/add.https.any.js
@@ -999,7 +999,7 @@
 ];
 
 if (navigator.ml) {
-  addTests.forEach((test) => {
+  addTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/arg_min_max.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/arg_min_max.https.any.js
index f0d38cb..33105b7 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/arg_min_max.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/arg_min_max.https.any.js
@@ -1825,7 +1825,7 @@
 ];
 
 if (navigator.ml) {
-  argMinMaxTests.forEach((test) => {
+  argMinMaxTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/averagePool2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/averagePool2d.https.any.js
index c112cd8..3637f50 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/averagePool2d.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/averagePool2d.https.any.js
@@ -1745,7 +1745,7 @@
 ];
 
 if (navigator.ml) {
-  averagePool2dTests.forEach((test) => {
+  averagePool2dTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/batch_normalization.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/batch_normalization.https.any.js
index b559cbc..dd23ccec 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/batch_normalization.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/batch_normalization.https.any.js
@@ -1367,7 +1367,7 @@
 ];
 
 if (navigator.ml) {
-  batchNormTests.forEach((test) => {
+  batchNormTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cast.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cast.https.any.js
index 8fd6298..0219420 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cast.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cast.https.any.js
@@ -1493,7 +1493,7 @@
 ];
 
 if (navigator.ml) {
-  castTests.forEach((test) => {
+  castTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getCastPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/ceil.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/ceil.https.any.js
index 7d487dd..20d8a4d 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/ceil.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/ceil.https.any.js
@@ -457,7 +457,7 @@
 ];
 
 if (navigator.ml) {
-  ceilTests.forEach((test) => {
+  ceilTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getCeilPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/clamp.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/clamp.https.any.js
index ebcec42..cf77b67 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/clamp.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/clamp.https.any.js
@@ -1926,7 +1926,7 @@
 ];
 
 if (navigator.ml) {
-  clampTests.forEach((test) => {
+  clampTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/concat.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/concat.https.any.js
index aaecaecc9..821a85e 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/concat.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/concat.https.any.js
@@ -2374,7 +2374,7 @@
 ];
 
 if (navigator.ml) {
-  concatTests.forEach((test) => {
+  concatTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/constant-reshape-optimization.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/constant-reshape-optimization.https.any.js
index eaa232b..3428772 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/constant-reshape-optimization.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/constant-reshape-optimization.https.any.js
@@ -87,7 +87,7 @@
 }];
 
 if (navigator.ml) {
-  tests.forEach((test) => {
+  tests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getInstanceNormPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv2d.https.any.js
index 45fecb2b..9962f21 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv2d.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv2d.https.any.js
@@ -2114,7 +2114,7 @@
 ];
 
 if (navigator.ml) {
-  conv2dTests.forEach((test) => {
+  conv2dTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.js
index a17df91..4e5525a 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any.js
@@ -3246,7 +3246,7 @@
 ];
 
 if (navigator.ml) {
-  convTranspose2dTests.forEach((test) => {
+  convTranspose2dTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cos.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cos.https.any.js
index 6926962d5..7804749 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cos.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cos.https.any.js
@@ -527,7 +527,7 @@
 ];
 
 if (navigator.ml) {
-  cosTests.forEach((test) => {
+  cosTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getCosPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cumulative_sum.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cumulative_sum.https.any.js
index 34a6251..4264b14e 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cumulative_sum.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/cumulative_sum.https.any.js
@@ -259,7 +259,7 @@
 ];
 
 if (navigator.ml) {
-  cumulativeSumTests.forEach((test) => {
+  cumulativeSumTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getCumulativeSumPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js
index 85f51e1..9ac74fc 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/dequantizeLinear.https.any.js
@@ -1468,7 +1468,7 @@
 ];
 
 if (navigator.ml) {
-  dequantizeLinearTests.forEach((test) => {
+  dequantizeLinearTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getDequantizeLinearPrecisionTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/div.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/div.https.any.js
index 1914c482..8749f9f 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/div.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/div.https.any.js
@@ -964,7 +964,7 @@
 ];
 
 if (navigator.ml) {
-  divTests.forEach((test) => {
+  divTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getDivPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/elu.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/elu.https.any.js
index 09cb0a9..b9692986 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/elu.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/elu.https.any.js
@@ -729,7 +729,7 @@
 ];
 
 if (navigator.ml) {
-  eluTests.forEach((test) => {
+  eluTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js
index 33d27cf..c2badc5 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/equal.https.any.js
@@ -977,7 +977,7 @@
 ];
 
 if (navigator.ml) {
-  equalTests.forEach((test) => {
+  equalTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/erf.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/erf.https.any.js
index 0c97253e..752623b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/erf.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/erf.https.any.js
@@ -529,7 +529,7 @@
 ];
 
 if (navigator.ml) {
-  erfTests.forEach((test) => {
+  erfTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getErfPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/exp.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/exp.https.any.js
index 0f9b648c..179d0e95 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/exp.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/exp.https.any.js
@@ -637,7 +637,7 @@
 ];
 
 if (navigator.ml) {
-  expTests.forEach((test) => {
+  expTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getExpPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/expand.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/expand.https.any.js
index f9040f25..b17c9c6 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/expand.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/expand.https.any.js
@@ -1329,7 +1329,7 @@
 ];
 
 if (navigator.ml) {
-  expandTests.forEach((test) => {
+  expandTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/floor.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/floor.https.any.js
index 50eaa31a..ccb0be8 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/floor.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/floor.https.any.js
@@ -457,7 +457,7 @@
 ];
 
 if (navigator.ml) {
-  floorTests.forEach((test) => {
+  floorTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getFloorPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gather.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gather.https.any.js
index 7f3c9c11..08a14f3b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gather.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gather.https.any.js
@@ -1702,7 +1702,7 @@
 ];
 
 if (navigator.ml) {
-  gatherTests.forEach((test) => {
+  gatherTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherElements.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherElements.https.any.js
index 2b13f59..565332aa 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherElements.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherElements.https.any.js
@@ -403,7 +403,7 @@
 ];
 
 if (navigator.ml) {
-  gatherElementsTests.forEach((test) => {
+  gatherElementsTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherND.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherND.https.any.js
index 41e1bc7..434410f 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherND.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gatherND.https.any.js
@@ -572,7 +572,7 @@
 ];
 
 if (navigator.ml) {
-  gatherNDTests.forEach((test) => {
+  gatherNDTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gelu.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gelu.https.any.js
index 23b70f1..9c06af3 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gelu.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gelu.https.any.js
@@ -503,7 +503,7 @@
 ];
 
 if (navigator.ml) {
-  geluTests.forEach((test) => {
+  geluTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gemm.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gemm.https.any.js
index b24c806..f9f15d65 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gemm.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gemm.https.any.js
@@ -2411,7 +2411,7 @@
 ];
 
 if (navigator.ml) {
-  gemmTests.forEach((test) => {
+  gemmTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js
index bf6f884..26723c1 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater.https.any.js
@@ -981,7 +981,7 @@
 ];
 
 if (navigator.ml) {
-  greaterTests.forEach((test) => {
+  greaterTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js
index 7dffe09..18f6b0c0 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/greater_or_equal.https.any.js
@@ -976,7 +976,7 @@
 ];
 
 if (navigator.ml) {
-  greaterOrEqualTests.forEach((test) => {
+  greaterOrEqualTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru.https.any.js
index 4118643..06ff4a5 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru.https.any.js
@@ -2005,7 +2005,7 @@
 ];
 
 if (navigator.ml) {
-  gruTests.forEach((test) => {
+  gruTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getGruPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru_cell.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru_cell.https.any.js
index 4e74520..8d2c599 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru_cell.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/gru_cell.https.any.js
@@ -608,7 +608,7 @@
 ];
 
 if (navigator.ml) {
-  gruCellTests.forEach((test) => {
+  gruCellTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getGruCellPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_sigmoid.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_sigmoid.https.any.js
index b5f6fd0..5ad5a815 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_sigmoid.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_sigmoid.https.any.js
@@ -1344,7 +1344,7 @@
 ];
 
 if (navigator.ml) {
-  hardSigmoidTests.forEach((test) => {
+  hardSigmoidTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_swish.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_swish.https.any.js
index e49ea6fd..02d902c 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_swish.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/hard_swish.https.any.js
@@ -646,7 +646,7 @@
 ];
 
 if (navigator.ml) {
-  hardSwishTests.forEach((test) => {
+  hardSwishTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/identity.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/identity.https.any.js
index be645fd..a68d0be7cd 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/identity.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/identity.https.any.js
@@ -521,7 +521,7 @@
 ];
 
 if (navigator.ml) {
-  identityTests.forEach((test) => {
+  identityTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/instance_normalization.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/instance_normalization.https.any.js
index 2766f914..0011a97 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/instance_normalization.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/instance_normalization.https.any.js
@@ -629,7 +629,7 @@
 ];
 
 if (navigator.ml) {
-  instanceNormTests.forEach((test) => {
+  instanceNormTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getInstanceNormPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/l2Pool2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/l2Pool2d.https.any.js
index f0e16be9..bb4d3d79 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/l2Pool2d.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/l2Pool2d.https.any.js
@@ -1358,7 +1358,7 @@
 ];
 
 if (navigator.ml) {
-  l2Pool2dTests.forEach((test) => {
+  l2Pool2dTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/layer_normalization.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/layer_normalization.https.any.js
index f22d044..d0f4f9a 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/layer_normalization.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/layer_normalization.https.any.js
@@ -1101,7 +1101,7 @@
 ];
 
 if (navigator.ml) {
-  layerNormTests.forEach((test) => {
+  layerNormTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getLayerNormPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/leaky_relu.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/leaky_relu.https.any.js
index 03c8985c..44ba712 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/leaky_relu.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/leaky_relu.https.any.js
@@ -875,7 +875,7 @@
 ];
 
 if (navigator.ml) {
-  leakyReluTests.forEach((test) => {
+  leakyReluTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js
index 0238a00f..d39c85b0 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser.https.any.js
@@ -988,7 +988,7 @@
 ];
 
 if (navigator.ml) {
-  lesserTests.forEach((test) => {
+  lesserTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js
index e268dd4..dfdb7bc 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lesser_or_equal.https.any.js
@@ -1095,7 +1095,7 @@
 ];
 
 if (navigator.ml) {
-  lesserOrEqualTests.forEach((test) => {
+  lesserOrEqualTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/linear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/linear.https.any.js
index 1f13fe17..794981d 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/linear.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/linear.https.any.js
@@ -1015,7 +1015,7 @@
 ];
 
 if (navigator.ml) {
-  linearTests.forEach((test) => {
+  linearTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js
index 8ed807b..055d600e 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/log.https.any.js
@@ -510,7 +510,7 @@
 ];
 
 if (navigator.ml) {
-  logTests.forEach((test) => {
+  logTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getLogPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js
index 40ba45d..823771c 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_and.https.any.js
@@ -413,7 +413,7 @@
 ];
 
 if (navigator.ml) {
-  logicalAndTests.forEach((test) => {
+  logicalAndTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js
index 5b0b8da..63bea6f 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_not.https.any.js
@@ -204,7 +204,7 @@
 ];
 
 if (navigator.ml) {
-  logicalNotTests.forEach((test) => {
+  logicalNotTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js
index 587a567..60c5942 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_or.https.any.js
@@ -413,7 +413,7 @@
 ];
 
 if (navigator.ml) {
-  logicalOrTests.forEach((test) => {
+  logicalOrTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js
index 423d36d..af5b5df 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/logical_xor.https.any.js
@@ -413,7 +413,7 @@
 ];
 
 if (navigator.ml) {
-  logicalXorTests.forEach((test) => {
+  logicalXorTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js
index 74e8cfb..8c0ed85 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm.https.any.js
@@ -1915,7 +1915,7 @@
 ];
 
 if (navigator.ml) {
-  lstmTests.forEach((test) => {
+  lstmTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getLstmPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm_cell.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm_cell.https.any.js
index a1d97ddf..345c516 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm_cell.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/lstm_cell.https.any.js
@@ -785,7 +785,7 @@
 ];
 
 if (navigator.ml) {
-  lstmCellTests.forEach((test) => {
+  lstmCellTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getLstmCellPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/matmul.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/matmul.https.any.js
index f452d59e..f5f79e3a 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/matmul.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/matmul.https.any.js
@@ -1096,7 +1096,7 @@
 ];
 
 if (navigator.ml) {
-  matmulTests.forEach((test) => {
+  matmulTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getMatmulPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/max.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/max.https.any.js
index bbea239..07d600a 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/max.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/max.https.any.js
@@ -921,7 +921,7 @@
 ];
 
 if (navigator.ml) {
-  maxTests.forEach((test) => {
+  maxTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/maxPool2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/maxPool2d.https.any.js
index 6ee8b197..6fecb3bf 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/maxPool2d.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/maxPool2d.https.any.js
@@ -1208,7 +1208,7 @@
 ];
 
 if (navigator.ml) {
-  maxPool2dTests.forEach((test) => {
+  maxPool2dTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/min.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/min.https.any.js
index 3abd2e6..41e8e43 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/min.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/min.https.any.js
@@ -931,7 +931,7 @@
 ];
 
 if (navigator.ml) {
-  minTests.forEach((test) => {
+  minTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mlNumber.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mlNumber.https.any.js
index 643d09b7..df778183 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mlNumber.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mlNumber.https.any.js
@@ -268,7 +268,7 @@
 ];
 
 if (navigator.ml) {
-  mlNumberTests.forEach((test) => {
+  mlNumberTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getClampPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mul.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mul.https.any.js
index f860684..a026584 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mul.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/mul.https.any.js
@@ -915,7 +915,7 @@
 ];
 
 if (navigator.ml) {
-  mulTests.forEach((test) => {
+  mulTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/neg.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/neg.https.any.js
index 5c5045d3..02ce396 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/neg.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/neg.https.any.js
@@ -636,7 +636,7 @@
 ];
 
 if (navigator.ml) {
-  negTests.forEach((test) => {
+  negTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getNegPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/not_equal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/not_equal.https.any.js
index e7440799..ee4f2de 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/not_equal.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/not_equal.https.any.js
@@ -978,7 +978,7 @@
 ];
 
 if (navigator.ml) {
-  notEqualTests.forEach((test) => {
+  notEqualTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getZeroULPTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pad.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pad.https.any.js
index ad33467..67fb911 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pad.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pad.https.any.js
@@ -1030,7 +1030,7 @@
 ];
 
 if (navigator.ml) {
-  padTests.forEach((test) => {
+  padTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pow.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pow.https.any.js
index f51feca4..cf895f4 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pow.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/pow.https.any.js
@@ -982,7 +982,7 @@
 ];
 
 if (navigator.ml) {
-  powTests.forEach((test) => {
+  powTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getPowPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/prelu.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/prelu.https.any.js
index cc6e005..5f64ff6 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/prelu.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/prelu.https.any.js
@@ -1241,7 +1241,7 @@
 ];
 
 if (navigator.ml) {
-  preluTests.forEach((test) => {
+  preluTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
index 8c81447d..0e747e7 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
@@ -20,12 +20,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'filter': {
@@ -35,12 +35,12 @@
         },
         'filterScale': {
           'data': [0.023458752938762234],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'filterZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'bias': {
@@ -60,12 +60,12 @@
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -151,12 +151,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'filter': {
@@ -166,12 +166,12 @@
         },
         'filterScale': {
           'data': [0.023458752938762234],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'filterZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'bias': {
@@ -191,12 +191,12 @@
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -290,12 +290,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'filter': {
@@ -305,12 +305,12 @@
         },
         'filterScale': {
           'data': [0.7114229798316956],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'filterZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'bias': {
@@ -330,12 +330,12 @@
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -431,12 +431,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'filter': {
@@ -448,12 +448,12 @@
         },
         'filterScale': {
           'data': [0.023458752938762234],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'filterZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'bias': {
@@ -473,12 +473,12 @@
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -571,12 +571,12 @@
         },
         'inputAScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -588,22 +588,22 @@
         },
         'inputBScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -688,12 +688,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'filter': {
@@ -703,12 +703,12 @@
         },
         'filterScale': {
           'data': [0.023458752938762234],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'filterZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'bias': {
@@ -728,12 +728,12 @@
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -836,12 +836,12 @@
         },
         'inputAScale': {
           'data': [0.617084980010986],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [120],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -853,22 +853,22 @@
         },
         'inputBScale': {
           'data': [0.617084980010986],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [120],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.617084980010986],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [120],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -946,12 +946,12 @@
         },
         'inputAScale': {
           'data': [0.3921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -964,22 +964,22 @@
         },
         'inputBScale': {
           'data': [0.3921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.3921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1057,12 +1057,12 @@
         },
         'inputAScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -1074,22 +1074,22 @@
         },
         'inputBScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1165,12 +1165,12 @@
         },
         'inputAScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -1182,22 +1182,22 @@
         },
         'inputBScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1281,12 +1281,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1359,12 +1359,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1437,12 +1437,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1515,12 +1515,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1593,12 +1593,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1671,12 +1671,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1741,12 +1741,12 @@
         },
         'inputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'gatherIndices': {
@@ -1828,12 +1828,12 @@
         },
         'inputAScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -1845,12 +1845,12 @@
         },
         'inputBScale': {
           'data': [0.023458752938762234],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputC': {
@@ -1872,12 +1872,12 @@
         },
         'outputScale': {
           'data': [0.3921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -1964,22 +1964,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2048,22 +2048,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2131,22 +2131,22 @@
         },
         'inputScale': {
           'data': [0.00390625],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.00390625],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2214,22 +2214,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2300,12 +2300,12 @@
         },
         'inputAScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputAZeroPoint': {
           'data': [127],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'inputB': {
@@ -2317,22 +2317,22 @@
         },
         'inputBScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputBZeroPoint': {
           'data': [127],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [127],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2414,22 +2414,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2497,22 +2497,22 @@
         },
         'inputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2579,22 +2579,22 @@
         },
         'inputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2661,22 +2661,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2745,22 +2745,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2871,22 +2871,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [16],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -2953,12 +2953,12 @@
         },
         'inputScale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
@@ -3019,22 +3019,22 @@
         },
         'inputScale': {
           'data': [0.00390625],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.00390625],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [-128],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3102,12 +3102,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
@@ -3184,12 +3184,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
@@ -3266,12 +3266,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
@@ -3348,12 +3348,12 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
@@ -3430,22 +3430,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1, 1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3519,22 +3519,22 @@
         },
         'inputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'inputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
         'outputScale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'outputZeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3613,12 +3613,12 @@
         },
         'scale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3697,12 +3697,12 @@
         },
         'scale': {
           'data': [0.003921568859368563],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3778,12 +3778,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3854,12 +3854,12 @@
         },
         'scale': {
           'data': [0.343092918395996],
-          'descriptor': {shape: [1], dataType: 'float32'},
+          'descriptor': {shape: [1, 1], dataType: 'float32'},
           'constant': true
         },
         'zeroPoint': {
           'data': [0],
-          'descriptor': {shape: [1], dataType: 'int8'},
+          'descriptor': {shape: [1, 1], dataType: 'int8'},
           'constant': true
         },
       },
@@ -3919,7 +3919,7 @@
 ];
 
 if (navigator.ml) {
-  subgraphTests.forEach((test) => {
+  subgraphTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js
index 7ba2fd4..95b43b51d 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/quantizeLinear.https.any.js
@@ -1169,7 +1169,7 @@
 ];
 
 if (navigator.ml) {
-  quantizeLinearTests.forEach((test) => {
+  quantizeLinearTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getQuantizeLinearPrecisionTolerance, test,
         /*cast_to_supported_type=*/true);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reciprocal.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reciprocal.https.any.js
index f21ec78..40a17940 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reciprocal.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reciprocal.https.any.js
@@ -553,7 +553,7 @@
 ];
 
 if (navigator.ml) {
-  reciprocalTests.forEach((test) => {
+  reciprocalTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getReciprocalPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l1.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l1.https.any.js
index d59909f..9465777 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l1.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l1.https.any.js
@@ -1187,7 +1187,7 @@
 ];
 
 if (navigator.ml) {
-  reduceL1Tests.forEach((test) => {
+  reduceL1Tests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l2.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l2.https.any.js
index 9ccd350..2a4e94a 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l2.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_l2.https.any.js
@@ -1127,7 +1127,7 @@
 ];
 
 if (navigator.ml) {
-  reduceL2Tests.forEach((test) => {
+  reduceL2Tests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum.https.any.js
index 714ba1c..6d98832 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum.https.any.js
@@ -1074,7 +1074,7 @@
 ];
 
 if (navigator.ml) {
-  reduceLogSumTests.forEach((test) => {
+  reduceLogSumTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum_exp.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum_exp.https.any.js
index 298e143..6770b74 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum_exp.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_log_sum_exp.https.any.js
@@ -1211,7 +1211,7 @@
 ];
 
 if (navigator.ml) {
-  reduceLogSumExpTests.forEach((test) => {
+  reduceLogSumExpTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_max.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_max.https.any.js
index 659641c..dc08e1c 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_max.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_max.https.any.js
@@ -994,7 +994,7 @@
 ];
 
 if (navigator.ml) {
-  reduceMaxTests.forEach((test) => {
+  reduceMaxTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_mean.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_mean.https.any.js
index 4851e51..a402c25 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_mean.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_mean.https.any.js
@@ -1155,7 +1155,7 @@
 ];
 
 if (navigator.ml) {
-  reduceMeanTests.forEach((test) => {
+  reduceMeanTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_min.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_min.https.any.js
index 42fc3e4..8e16045 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_min.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_min.https.any.js
@@ -994,7 +994,7 @@
 ];
 
 if (navigator.ml) {
-  reduceMinTests.forEach((test) => {
+  reduceMinTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_product.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_product.https.any.js
index 17ee27ed..cb1f16d 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_product.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_product.https.any.js
@@ -1034,7 +1034,7 @@
 ];
 
 if (navigator.ml) {
-  reduceProductTests.forEach((test) => {
+  reduceProductTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum.https.any.js
index 1d6f944..d4120ac 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum.https.any.js
@@ -1129,7 +1129,7 @@
 ];
 
 if (navigator.ml) {
-  reduceSumTests.forEach((test) => {
+  reduceSumTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum_square.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum_square.https.any.js
index 73762e4b..167f4f3 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum_square.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reduce_sum_square.https.any.js
@@ -1215,7 +1215,7 @@
 ];
 
 if (navigator.ml) {
-  reduceSumSquareTests.forEach((test) => {
+  reduceSumSquareTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/relu.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/relu.https.any.js
index 05e9e32..d6fda23 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/relu.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/relu.https.any.js
@@ -667,7 +667,7 @@
 ];
 
 if (navigator.ml) {
-  reluTests.forEach((test) => {
+  reluTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/resample2d.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/resample2d.https.any.js
index fe50b8c..7872bd2 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/resample2d.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/resample2d.https.any.js
@@ -518,7 +518,7 @@
 ];
 
 if (navigator.ml) {
-  resample2dTests.forEach((test) => {
+  resample2dTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reshape.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reshape.https.any.js
index e54d0f6..d9fa87f 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reshape.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reshape.https.any.js
@@ -2362,7 +2362,7 @@
 ];
 
 if (navigator.ml) {
-  reshapeTests.forEach((test) => {
+  reshapeTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reverse.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reverse.https.any.js
index 3b1d8bf..9d6fccad 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reverse.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/reverse.https.any.js
@@ -263,7 +263,7 @@
 ];
 
 if (navigator.ml) {
-  reverseTests.forEach((test) => {
+  reverseTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterElements.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterElements.https.any.js
index e76494b..a388ad1 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterElements.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterElements.https.any.js
@@ -282,7 +282,7 @@
 ];
 
 if (navigator.ml) {
-  scatterElementsTests.forEach((test) => {
+  scatterElementsTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterND.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterND.https.any.js
index 93b5ca5..919639b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterND.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/scatterND.https.any.js
@@ -164,7 +164,7 @@
 ];
 
 if (navigator.ml) {
-  scatterNDTests.forEach((test) => {
+  scatterNDTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sigmoid.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sigmoid.https.any.js
index 7474fe9..a8a310e 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sigmoid.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sigmoid.https.any.js
@@ -630,7 +630,7 @@
 ];
 
 if (navigator.ml) {
-  sigmoidTests.forEach((test) => {
+  sigmoidTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js
index 004c03b..d61ce38 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sign.https.any.js
@@ -188,7 +188,7 @@
 ];
 
 if (navigator.ml) {
-  signTests.forEach((test) => {
+  signTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getSignPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sin.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sin.https.any.js
index a614852..1f9a5eaa 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sin.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sin.https.any.js
@@ -533,7 +533,7 @@
 ];
 
 if (navigator.ml) {
-  sinTests.forEach((test) => {
+  sinTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getSinPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/slice.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/slice.https.any.js
index 7603e47..b1a30fc8 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/slice.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/slice.https.any.js
@@ -626,7 +626,7 @@
 ];
 
 if (navigator.ml) {
-  sliceTests.forEach((test) => {
+  sliceTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softmax.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softmax.https.any.js
index 33c2e1db..2d9f28d 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softmax.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softmax.https.any.js
@@ -365,7 +365,7 @@
 ];
 
 if (navigator.ml) {
-  softmaxTests.forEach((test) => {
+  softmaxTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softplus.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softplus.https.any.js
index 36386c0..ba8b8f3 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softplus.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softplus.https.any.js
@@ -508,7 +508,7 @@
 ];
 
 if (navigator.ml) {
-  softplusTests.forEach((test) => {
+  softplusTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softsign.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softsign.https.any.js
index cf06bbc4..9c7c4d1 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softsign.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/softsign.https.any.js
@@ -647,7 +647,7 @@
 ];
 
 if (navigator.ml) {
-  softsignTests.forEach((test) => {
+  softsignTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/split.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/split.https.any.js
index 925ba62..a6695e20 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/split.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/split.https.any.js
@@ -919,7 +919,7 @@
 ];
 
 if (navigator.ml) {
-  splitTests.forEach((test) => {
+  splitTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sqrt.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sqrt.https.any.js
index 57cf5e8..f56dde6 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sqrt.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sqrt.https.any.js
@@ -515,7 +515,7 @@
 ];
 
 if (navigator.ml) {
-  sqrtTests.forEach((test) => {
+  sqrtTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getSqrtPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sub.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sub.https.any.js
index 31d5e9fb..d93acf5 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sub.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/sub.https.any.js
@@ -1114,7 +1114,7 @@
 ];
 
 if (navigator.ml) {
-  subTests.forEach((test) => {
+  subTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/subgraph.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/subgraph.https.any.js
index 8a0b7fa..dd361692 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/subgraph.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/subgraph.https.any.js
@@ -2565,7 +2565,7 @@
 ];
 
 if (navigator.ml) {
-  subgraphTests.forEach((test) => {
+  subgraphTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tan.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tan.https.any.js
index 054be65..79194b3 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tan.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tan.https.any.js
@@ -533,7 +533,7 @@
 ];
 
 if (navigator.ml) {
-  tanTests.forEach((test) => {
+  tanTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getTanPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tanh.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tanh.https.any.js
index 88d48e9..6d61fd5 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tanh.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tanh.https.any.js
@@ -586,7 +586,7 @@
 ];
 
 if (navigator.ml) {
-  tanhTests.forEach((test) => {
+  tanhTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getPrecisionTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tile.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tile.https.any.js
index 3e4ea39..fae0c07 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tile.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/tile.https.any.js
@@ -163,7 +163,7 @@
 ];
 
 if (navigator.ml) {
-  tileTests.forEach((test) => {
+  tileTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/transpose.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/transpose.https.any.js
index 27b7e74..e50317d 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/transpose.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/transpose.https.any.js
@@ -696,7 +696,7 @@
 ];
 
 if (navigator.ml) {
-  transposeTests.forEach((test) => {
+  transposeTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(buildAndExecuteGraph, getZeroULPTolerance, test);
   });
 } else {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/triangular.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/triangular.https.any.js
index 8006672..2e5ea0dd 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/triangular.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/triangular.https.any.js
@@ -1308,7 +1308,7 @@
 ];
 
 if (navigator.ml) {
-  triangularTests.forEach((test) => {
+  triangularTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getTriangularPrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/where.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/where.https.any.js
index 21975b4..1100fdd 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/where.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/where.https.any.js
@@ -1838,7 +1838,7 @@
 ];
 
 if (navigator.ml) {
-  whereTests.forEach((test) => {
+  whereTests.filter(isTargetTest).forEach((test) => {
     webnn_conformance_test(
         buildAndExecuteGraph, getWherePrecisionTolerance, test);
   });
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
index 1e7b5a9..c2af1ad7 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
@@ -195,9 +195,16 @@
   },
 };
 
-const variant = location.search.substring(1);
+const searchParams = new URLSearchParams(location.search);
+const variant = searchParams.get('device') || location.search.substring(1);
 const contextOptions = kContextOptionsForVariant[variant];
 
+const tcNameArray = searchParams.getAll('tc');
+
+function isTargetTest(test) {
+  return tcNameArray.length === 0 || tcNameArray.includes(test.name);
+}
+
 const assertDescriptorsEquals = (outputOperand, expected) => {
   const dataType =
       expected.castedType ? expected.castedType : expected.dataType;
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.js
index a3af5b8..acd2b85 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/dequantizeLinear.https.any.js
@@ -20,18 +20,18 @@
   },
   {
     name:
-        '[dequantizeLinear] Test scale\'s shape = [5] and zeroPoint\'s shape = [5] which is unidirectionally broadcastable to input\'s shape.',
+        '[dequantizeLinear] Test scale\'s shape = [1, 1, 5] and zeroPoint\'s shape = [1, 1, 5] which is unidirectionally broadcastable to input\'s shape.',
     input: {dataType: 'int8', shape: [3, 2, 5]},
-    scale: {dataType: 'float32', shape: [5]},
-    zeroPoint: {dataType: 'int8', shape: [5]},
+    scale: {dataType: 'float32', shape: [1, 1, 5]},
+    zeroPoint: {dataType: 'int8', shape: [1, 1, 5]},
     output: {dataType: 'float32', shape: [3, 2, 5]},
   },
   {
     name:
-        '[dequantizeLinear] Test scale\'s shape = [] and zeroPoint\'s shape = [] which is unidirectionally broadcastable to input\'s shape.',
+        '[dequantizeLinear] Test scale\'s shape = [1, 1, 1] and zeroPoint\'s shape = [1, 1, 1] which is unidirectionally broadcastable to input\'s shape.',
     input: {dataType: 'uint8', shape: [3, 2, 5]},
-    scale: {dataType: 'float32', shape: []},
-    zeroPoint: {dataType: 'uint8', shape: []},
+    scale: {dataType: 'float32', shape: [1, 1, 1]},
+    zeroPoint: {dataType: 'uint8', shape: [1, 1, 1]},
     output: {dataType: 'float32', shape: [3, 2, 5]},
   },
   {
@@ -44,6 +44,13 @@
   },
   {
     name:
+        '[dequantizeLinear] Throw if the scale rank is not equal to input rank.',
+    input: {dataType: 'uint8', shape: [3, 2, 5]},
+    scale: {dataType: 'float32', shape: [5]},
+    zeroPoint: {dataType: 'uint8', shape: [5]},
+  },
+  {
+    name:
         '[dequantizeLinear] Throw if the scale size is not a factor of input size.',
     input: {dataType: 'uint8', shape: [3, 2, 5]},
     scale: {dataType: 'float32', shape: [2]},
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/quantizeLinear.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/quantizeLinear.https.any.js
index 5c96cfe0..518246a8 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/quantizeLinear.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/quantizeLinear.https.any.js
@@ -18,18 +18,18 @@
   },
   {
     name:
-        '[quantizeLinear] Test scale\'s shape = [5] and zeroPoint\'s shape = [5] which is unidirectionally broadcastable to input\'s shape.',
+        '[quantizeLinear] Test scale\'s shape = [1, 1, 5] and zeroPoint\'s shape = [1, 1, 5] which is unidirectionally broadcastable to input\'s shape.',
     input: {dataType: 'float32', shape: [3, 2, 5]},
-    scale: {dataType: 'float32', shape: [5]},
-    zeroPoint: {dataType: 'int8', shape: [5]},
+    scale: {dataType: 'float32', shape: [1, 1, 5]},
+    zeroPoint: {dataType: 'int8', shape: [1, 1, 5]},
     output: {dataType: 'int8', shape: [3, 2, 5]},
   },
   {
     name:
-        '[quantizeLinear] Test scale\'s shape = [] and zeroPoint\'s shape = [] which is unidirectionally broadcastable to input\'s shape.',
+        '[quantizeLinear] Test scale\'s shape = [1, 1, 1] and zeroPoint\'s shape = [1, 1, 1] which is unidirectionally broadcastable to input\'s shape.',
     input: {dataType: 'float32', shape: [3, 2, 5]},
-    scale: {dataType: 'float32', shape: []},
-    zeroPoint: {dataType: 'int8', shape: []},
+    scale: {dataType: 'float32', shape: [1, 1, 1]},
+    zeroPoint: {dataType: 'int8', shape: [1, 1, 1]},
     output: {dataType: 'int8', shape: [3, 2, 5]},
   },
   {
@@ -42,6 +42,13 @@
   },
   {
     name:
+        '[quantizeLinear] Throw if the scale rank is not equal to input rank.',
+    input: {dataType: 'float32', shape: [3, 2, 5]},
+    scale: {dataType: 'float32', shape: [5]},
+    zeroPoint: {dataType: 'int8', shape: [5]},
+  },
+  {
+    name:
         '[quantizeLinear] Throw if the scale size is not a factor of input size.',
     input: {dataType: 'float32', shape: [3, 2, 5]},
     scale: {dataType: 'float32', shape: [2, 1, 5]},
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-worker-GC.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-worker-GC.html
new file mode 100644
index 0000000..dffc170f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-worker-GC.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/gc.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+<script>
+'use strict';
+
+// Check that a worker RTCDataChannel is not collected by GC while observing remote pc close
+
+const worker = new Worker(`data:text/javascript,(${work.toString()})()`);
+
+async function didRemotePcClose(t, closeRemotePc) {
+  let pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();
+  t.add_cleanup(async () => await garbageCollect());
+  pc1.onicecandidate = e => pc2?.addIceCandidate(e?.candidate);
+  pc2.onicecandidate = e => pc1?.addIceCandidate(e?.candidate);
+  let dc1 = pc1.createDataChannel("");
+  worker.postMessage({channel: dc1}, [dc1]);
+  dc1 = null;
+  const haveClosed = new Promise(r => worker.onmessage = r);
+  await pc1.setLocalDescription();
+  await pc2.setRemoteDescription(pc1.localDescription);
+  await pc2.setLocalDescription();
+  await pc1.setRemoteDescription(pc2.localDescription);
+  if (closeRemotePc) pc2.close();
+  pc1 = pc2 = null;
+  await garbageCollect();
+  await Promise.race([haveClosed, new Promise(r => t.step_timeout(r, 10000))]);
+  return closed;
+}
+
+promise_test(async t => {
+  assert_true(await didRemotePcClose(t, true));
+}, "Control: detected remote PC being closed using a worker data channel");
+
+promise_test(async t => {
+  assert_false(await didRemotePcClose(t, false));
+}, "While remote PC remains open, its worker datachannel should not be collected");
+
+function work() {
+  onmessage = ({data: {channel}}) => {
+    if (channel) {
+      channel.onopen = () => assert_true(true, "worker: open");
+      channel.onclose = () => {
+        assert_true(true, "worker: close");
+        self.postMessage(true);
+      }
+    }
+  };
+}
+</script>
+</body>
+</html>
+
diff --git a/third_party/blink/web_tests/fast/css/h1-in-section-elements.html b/third_party/blink/web_tests/fast/css/h1-in-section-elements.html
deleted file mode 100644
index 4a38004..0000000
--- a/third_party/blink/web_tests/fast/css/h1-in-section-elements.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<head>
-<style>
-hr {
-    margin: 0;
-}
-
-h1, h2, h3, h4, h5, h6 {
-    border: solid 1px lime;
-}
-
-</style>
-</head>
-<body>
-<p>For each of pairs, the first one and the second one should be identical.
-<!-- This test should be converted to a reftest in the future! -->
-
-<table border=0 style="float:left">
-<tr><td><section><hr><h1>MMM</h1><hr></section>
-    <td><hr><h2>MMM</h2><hr>
-<tr><td><article><section><hr><h1>MMM</h1><hr></section></article>
-    <td><hr><h3>MMM</h3><hr>
-<tr><td><nav><article><section><hr><h1>MMM</h1><hr></section></article></nav>
-    <td><hr><h4>MMM</h4><hr>
-<tr><td><nav><aside><article><section><hr><h1>MMM</h1><hr></section></article></aside></nav>
-    <td><hr><h5>MMM</h5><hr>
-<tr><td><section><div><nav><aside><article><section><hr><h1>MMM</h1><hr></section></article></aside></nav><div></section>
-    <td><hr><h6>MMM</h6><hr>
-</table>
-<table border=0 style="-webkit-writing-mode: vertical-rl">
-<tr><td><section><hr><h1>MMM</h1><hr></section>
-    <td><hr><h2>MMM</h2><hr>
-<tr><td><article><section><hr><h1>MMM</h1><hr></section></article>
-    <td><hr><h3>MMM</h3><hr>
-<tr><td><nav><article><section><hr><h1>MMM</h1><hr></section></article></nav>
-    <td><hr><h4>MMM</h4><hr>
-<tr><td><nav><aside><article><section><hr><h1>MMM</h1><hr></section></article></aside></nav>
-    <td><hr><h5>MMM</h5><hr>
-<tr><td><section><div><nav><aside><article><section><hr><h1>MMM</h1><hr></section></article></aside></nav><div></section>
-    <td><hr><h6>MMM</h6><hr>
-</table>
-</body>
diff --git a/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt b/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt
index 50f550a..e4d4daa 100644
--- a/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/copy-network-request-expected.txt
@@ -323,7 +323,7 @@
 cURL Windows:
 curl ^"http://example.org/path^" ^
   -H ^"Content-Type: application/binary^" ^
-  --data-raw ^"^^€^^ÿ	^܀^"
+  --data-raw ^"^^€^^ÿ^	^܀^"
 
 
 cURL Unix:
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/h1-within-section-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/h1-within-section-expected.txt
deleted file mode 100644
index ea6702739..0000000
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/h1-within-section-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Verifies that H1 within section (without font overrides) triggers a deprecation issue.
-Inspector issue: {
-    issue : {
-        code : DeprecationIssue
-        details : {
-            deprecationIssueDetails : {
-                affectedFrame : {
-                    frameId : <string>
-                }
-                sourceCodeLocation : {
-                    columnNumber : 0
-                    lineNumber : -1
-                    url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html
-                }
-                type : H1UserAgentFontSizeInSection
-            }
-        }
-    }
-}
-
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/h1-within-section.js b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/h1-within-section.js
deleted file mode 100644
index 05ad294e..0000000
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/h1-within-section.js
+++ /dev/null
@@ -1,20 +0,0 @@
-(async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
-  // TODO(crbug.com/394111284) If/when the special H1 font rules are removed, this test can be deleted.
-  const { session, dp } = await testRunner.startBlank(
-  'Verifies that H1 within section (without font overrides) triggers a deprecation issue.');
-
-  await dp.Audits.enable();
-  const promise = dp.Audits.onceIssueAdded();
-  session.evaluate(`
-    const section = document.createElement('section');
-    const h1 = document.createElement('h1');
-    section.appendChild(h1);
-    document.body.appendChild(section);
-  `);
-
-  const result = await promise;
-  testRunner.log(result.params, 'Inspector issue: ');
-  testRunner.completeTest();
-})
-
-
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/dom-edit-copy-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom/dom-edit-copy-expected.txt
new file mode 100644
index 0000000..d2295260
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/dom-edit-copy-expected.txt
@@ -0,0 +1,15 @@
+Tests that copying + editing <body> does not crash.
+{
+    id : <number>
+    result : {
+    }
+    sessionId : <string>
+}
+{
+    id : <number>
+    result : {
+    }
+    sessionId : <string>
+}
+Survived
+
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/dom-edit-copy.js b/third_party/blink/web_tests/inspector-protocol/dom/dom-edit-copy.js
new file mode 100644
index 0000000..44daf01f73
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/dom-edit-copy.js
@@ -0,0 +1,16 @@
+(async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
+  var {page, session, dp} = await testRunner.startHTML(
+      `<html><body>contents</body></html>`, 'Tests that copying + editing <body> does not crash.');
+  const {result: {root: {nodeId}}} = await dp.DOM.getDocument();
+  const {result: body} = await dp.DOM.querySelector({nodeId, selector: 'body'});
+  const {result: html} = await dp.DOM.querySelector({nodeId, selector: 'html'});
+
+  const {result: {nodeId: newId}} =
+      await dp.DOM.copyTo({nodeId: body.nodeId, targetNodeId: html.nodeId});
+  testRunner.log(
+      await dp.DOM.setOuterHTML({nodeId: newId, outerHTML: '<a>a</a>'}));
+  testRunner.log(
+      await dp.DOM.setOuterHTML({nodeId: newId, outerHTML: '<b>b</b>'}));
+  testRunner.log('Survived');
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png
index b3e017c3..59cc5d0 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/webfont-synthetic-bold-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/webfont-synthetic-bold-expected.png
index 48a2684..f933f48 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/webfont-synthetic-bold-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/mlNumber.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/mlNumber.https.any_gpu-expected.txt
new file mode 100644
index 0000000..4e78a17
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/mlNumber.https.any_gpu-expected.txt
@@ -0,0 +1,23 @@
+This is a testharness.js-based test.
+[FAIL] cast BigInt to int64
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int64 must be one of [float32,float16]."
+[FAIL] cast BigInt to int64 overflow
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int64 must be one of [float32,float16]."
+[FAIL] cast BigInt to int64 underflow
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int64 must be one of [float32,float16]."
+[FAIL] cast BigInt to uint64
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type uint64 must be one of [float32,float16]."
+[FAIL] cast BigInt to uint64 overflow
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type uint64 must be one of [float32,float16]."
+[FAIL] cast BigInt to uint64 underflow
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type uint64 must be one of [float32,float16]."
+[FAIL] cast float to integer
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type uint64 must be one of [float32,float16]."
+[FAIL] cast float to integer overflows
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type uint8 must be one of [float32,float16]."
+[FAIL] cast float to integer underflows
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type uint8 must be one of [float32,float16]."
+[FAIL] cast fractional float to integer
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int64 must be one of [float32,float16]."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_cpu-expected.txt
index 1e1dd6f..08307d4 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_cpu-expected.txt
@@ -1,12 +1,14 @@
 This is a testharness.js-based test.
 [FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'input', must be one of [float32, float16, int32]."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] [dequantizeLinear] Test scale's shape = [1, 1, 5] and zeroPoint's shape = [1, 1, 5] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'input', must be one of [float32, float16, int32]."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] [dequantizeLinear] Test scale's shape = [1, 1, 1] and zeroPoint's shape = [1, 1, 1] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Test block-wise quantization with block_size = [2, 2, 5].
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
+[FAIL] [dequantizeLinear] Throw if the scale rank is not equal to input rank.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Throw if the scale size is not a factor of input size.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Throw if the shape of zero_point is not the same as the shape of input.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_cpu-expected.txt
index 2279c997..4369bf5e 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_cpu-expected.txt
@@ -1,12 +1,14 @@
 This is a testharness.js-based test.
 [FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] [quantizeLinear] Test scale's shape = [1, 1, 5] and zeroPoint's shape = [1, 1, 5] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] [quantizeLinear] Test scale's shape = [1, 1, 1] and zeroPoint's shape = [1, 1, 1] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Test block-wise quantization with block_size = [3, 2, 5].
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
+[FAIL] [quantizeLinear] Throw if the scale rank is not equal to input rank.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Throw if the scale size is not a factor of input size.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Throw if the shape of zero_point is not the same as the shape of input.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_npu-expected.txt
index 1e1dd6f..08307d4 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_npu-expected.txt
@@ -1,12 +1,14 @@
 This is a testharness.js-based test.
 [FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'input', must be one of [float32, float16, int32]."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] [dequantizeLinear] Test scale's shape = [1, 1, 5] and zeroPoint's shape = [1, 1, 5] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'input', must be one of [float32, float16, int32]."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] [dequantizeLinear] Test scale's shape = [1, 1, 1] and zeroPoint's shape = [1, 1, 1] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Test block-wise quantization with block_size = [2, 2, 5].
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
+[FAIL] [dequantizeLinear] Throw if the scale rank is not equal to input rank.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Throw if the scale size is not a factor of input size.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Throw if the shape of zero_point is not the same as the shape of input.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_npu-expected.txt
index 2279c997..4369bf5e 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_npu-expected.txt
@@ -1,12 +1,14 @@
 This is a testharness.js-based test.
 [FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] [quantizeLinear] Test scale's shape = [1, 1, 5] and zeroPoint's shape = [1, 1, 5] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] [quantizeLinear] Test scale's shape = [1, 1, 1] and zeroPoint's shape = [1, 1, 1] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Test block-wise quantization with block_size = [3, 2, 5].
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
+[FAIL] [quantizeLinear] Throw if the scale rank is not equal to input rank.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Throw if the scale size is not a factor of input size.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Throw if the shape of zero_point is not the same as the shape of input.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt
index 1e1dd6f..08307d4 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/dequantizeLinear.https.any_gpu-expected.txt
@@ -1,12 +1,14 @@
 This is a testharness.js-based test.
 [FAIL] [dequantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'input', must be one of [float32, float16, int32]."
-[FAIL] [dequantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] [dequantizeLinear] Test scale's shape = [1, 1, 5] and zeroPoint's shape = [1, 1, 5] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'input', must be one of [float32, float16, int32]."
-[FAIL] [dequantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] [dequantizeLinear] Test scale's shape = [1, 1, 1] and zeroPoint's shape = [1, 1, 1] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Test block-wise quantization with block_size = [2, 2, 5].
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
+[FAIL] [dequantizeLinear] Throw if the scale rank is not equal to input rank.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Throw if the scale size is not a factor of input size.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type uint8 for input operand named 'input', must be one of [float32, float16, int32]."
 [FAIL] [dequantizeLinear] Throw if the shape of zero_point is not the same as the shape of input.
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt
index 2279c997..4369bf5e 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/validation_tests/quantizeLinear.https.any_gpu-expected.txt
@@ -1,12 +1,14 @@
 This is a testharness.js-based test.
 [FAIL] [quantizeLinear] Test scale's shape = [3, 2, 5] and zeroPoint's shape = [3, 2, 5] which is the same as input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
-[FAIL] [quantizeLinear] Test scale's shape = [5] and zeroPoint's shape = [5] which is unidirectionally broadcastable to input's shape.
+[FAIL] [quantizeLinear] Test scale's shape = [1, 1, 5] and zeroPoint's shape = [1, 1, 5] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
-[FAIL] [quantizeLinear] Test scale's shape = [] and zeroPoint's shape = [] which is unidirectionally broadcastable to input's shape.
+[FAIL] [quantizeLinear] Test scale's shape = [1, 1, 1] and zeroPoint's shape = [1, 1, 1] which is unidirectionally broadcastable to input's shape.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Test block-wise quantization with block_size = [3, 2, 5].
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
+[FAIL] [quantizeLinear] Throw if the scale rank is not equal to input rank.
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Throw if the scale size is not a factor of input size.
   promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'input' on 'MLGraphBuilder': Unsupported data type int8 for input operand named 'zeroPoint', must be one of [float32, float16, int32]."
 [FAIL] [quantizeLinear] Throw if the shape of zero_point is not the same as the shape of input.
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/webfont-synthetic-bold-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/webfont-synthetic-bold-expected.png
index 41c56399..b1c78f83 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/webfont-synthetic-bold-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/text-antialias/webfont-synthetic-bold-expected.png b/third_party/blink/web_tests/platform/win/virtual/text-antialias/webfont-synthetic-bold-expected.png
index 9e7fbbd..b236b68b 100644
--- a/third_party/blink/web_tests/platform/win/virtual/text-antialias/webfont-synthetic-bold-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/text-antialias/webfont-synthetic-bold-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png b/third_party/blink/web_tests/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png
index 6d3aaf0..1eaf566 100644
--- a/third_party/blink/web_tests/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png
+++ b/third_party/blink/web_tests/virtual/text-antialias/sub-pixel/text-scaling-pixel-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index ed035b83..81c2c32 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -304,6 +304,7 @@
     property parentElement
     property parentNode
     property part
+    property patchSelf
     property popover
     property prefix
     property prepend
@@ -1591,6 +1592,7 @@
     property parentElement
     property parentNode
     property part
+    property patchSelf
     property prefix
     property prepend
     property previousElementSibling
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 8089570..ed547dd 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
@@ -2178,6 +2178,7 @@
     method importNode
     method moveBefore
     method open
+    method patchSelf
     method prepend
     method queryCommandEnabled
     method queryCommandIndeterm
@@ -2346,6 +2347,7 @@
     method getElementById
     method getPartRoot
     method moveBefore
+    method patchSelf
     method prepend
     method querySelector
     method querySelectorAll
@@ -2551,6 +2553,7 @@
     method insertAdjacentText
     method matches
     method moveBefore
+    method patchSelf
     method prepend
     method pseudo
     method querySelector
diff --git a/third_party/blink/web_tests/wpt_internal/IndexedDB/blob-valid-after-concurrent-abort.any.js b/third_party/blink/web_tests/wpt_internal/IndexedDB/blob-valid-after-concurrent-abort.any.js
new file mode 100644
index 0000000..f011e17
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/IndexedDB/blob-valid-after-concurrent-abort.any.js
@@ -0,0 +1,65 @@
+// META: title=Blob Valid After concurrent txn abort
+// META: global=window,worker
+// META: script=/IndexedDB/resources/support.js
+
+let key = 'key';
+
+// This is an internal test because it relies on transactions being run
+// concurrently, which is not technically required by the spec.
+indexeddb_test(
+  function upgrade(t, db) {
+    db.createObjectStore('store');
+    db.createObjectStore('logs');
+  },
+  function success(t, db) {
+    const blobAContent = 'Blob A content';
+    const blobA = new Blob([blobAContent], { 'type': 'text/plain' });
+    const value = { a0: blobA };
+
+    // Begin by writing a blob and committing.
+    const txn = db.transaction('store', 'readwrite')
+    txn.objectStore('store').put(value, key);
+    txn.oncomplete = t.step_func(() => {
+      // Start a new RW transaction.
+      const txn2 = db.transaction('logs', 'readwrite');
+      txn2.onsuccess = t.unreached_func();
+      let readBlob;
+      // Keep it alive while the readonly transaction executes.
+      const doWrite = () => {
+        if (readBlob) {
+          return;
+        }
+        const writeRequest = txn2.objectStore('logs').put('hello', 'world');
+        writeRequest.onsuccess = doWrite;
+      };
+      doWrite();
+
+      // Start a RO transaction which can be concurrent since it has non-
+      // overlapping scope.
+      const ro_txn = db.transaction('store', 'readonly');
+      const store = ro_txn.objectStore('store');
+      const request = store.get(key);
+      // Get the blob in this transaction, but don't read it yet.
+      request.onsuccess = () => {
+        readBlob = request.result.a0;
+        // Abort the concurrent RW transaction. If the implementation is not
+        // careful, this could invalidate the reference added for the active
+        // blob.
+        txn2.abort();
+      };
+
+      // Now delete the blob from the database, then try to read it. The
+      // existence of the blob reference should keep the bytes alive and
+      // readable.
+      const txn3 = db.transaction('store', 'readwrite');
+      const writeRequest3 = txn3.objectStore('store').put('overwrite', key);
+      writeRequest3.onsuccess = t.step_func(() => {
+        readBlob.text().then(
+          t.step_func_done(text => {
+            assert_equals(text, blobAContent);
+          }),
+          t.unreached_func());
+      });
+    });
+  },
+  'The blob reference returned by a RO transaction should stay valid even if a concurrent RW transaction is aborted');
diff --git a/third_party/cardboard/BUILD.gn b/third_party/cardboard/BUILD.gn
index 5d2aabf..0fd3dacc 100644
--- a/third_party/cardboard/BUILD.gn
+++ b/third_party/cardboard/BUILD.gn
@@ -153,4 +153,6 @@
     "android",
     "log",
   ]
+
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
 }
diff --git a/third_party/catapult b/third_party/catapult
index ed07b40..5b2aa83 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit ed07b403a26d3ba2cfe407e84716464b8899e575
+Subproject commit 5b2aa8309e962decb237aefa7e3c39df5f38dfcf
diff --git a/third_party/compiler-rt/src b/third_party/compiler-rt/src
index f11321e..e2bc292 160000
--- a/third_party/compiler-rt/src
+++ b/third_party/compiler-rt/src
@@ -1 +1 @@
-Subproject commit f11321e08af04e3f216748afad3029e51637190b
+Subproject commit e2bc292b58607041c610185f2a06709fcb566bd5
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 5ce80c8..9cf131b 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 5ce80c825163a9545f9c7d3f5446d0795a0c25fe
+Subproject commit 9cf131bdaadf7fe5c6b536036be8b730a41f839c
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index eb970fb..2f76052 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit eb970fbc6482f281b95bbec1c33c1c539f6d50f0
+Subproject commit 2f76052f2c9f0794d6327b641a00327f43a023a0
diff --git a/third_party/fontconfig/BUILD.gn b/third_party/fontconfig/BUILD.gn
index ad1ed2d5..acb6c6a0 100644
--- a/third_party/fontconfig/BUILD.gn
+++ b/third_party/fontconfig/BUILD.gn
@@ -28,6 +28,8 @@
     bindgen_flags = [
       "merge-extern-blocks",
       "allowlist-item=(FcPattern.*|FcRange.*|FcCharSet.*|FcLangSetFromCharSet|FC_.*_OBJECT)",
+      "blocklist-type=(FcCharSet|FcLangSet)",
+      "raw-line=pub use fontconfig_bindings::FcCharSet; pub use fontconfig_bindings::FcLangSet;",
     ]
     crate_name = "fcint_bindings"
     deps = [ ":fontconfig_h_bindgen" ]
diff --git a/third_party/fontconfig/README.chromium b/third_party/fontconfig/README.chromium
index 6d56036..d4fe9ac 100644
--- a/third_party/fontconfig/README.chromium
+++ b/third_party/fontconfig/README.chromium
@@ -1,7 +1,7 @@
 Name: fontconfig
 URL: http://www.freedesktop.org/wiki/Software/fontconfig/
-Version: c527fe1452d469e5fa1a211180dd40bcdb79fb2a
-CPEPrefix: cpe:/a:fontconfig_project:fontconfig:2.16.2
+Version: 8f169b6a9c6be7e8f1fa3480d93b33befa6bee3f
+CPEPrefix: cpe:/a:fontconfig_project:fontconfig:2.17.1
 License: public-domain-md5, MIT-Modern-Variant, HPND-sell-variant, MIT
 License File: src/COPYING
 Security Critical: yes
diff --git a/third_party/fontconfig/include/fc-lang/fclang.h b/third_party/fontconfig/include/fc-lang/fclang.h
index 95bafdf..67288b3 100644
--- a/third_party/fontconfig/include/fc-lang/fclang.h
+++ b/third_party/fontconfig/include/fc-lang/fclang.h
@@ -22,11 +22,11 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* total size: 1658 unique leaves: 742 */
+/* total size: 1659 unique leaves: 743 */
 
-#define LEAF0       (281 * sizeof (FcLangCharSet))
-#define OFF0        (LEAF0 + 742 * sizeof (FcCharLeaf))
-#define NUM0        (OFF0 + 886 * sizeof (uintptr_t))
+#define LEAF0       (282 * sizeof (FcLangCharSet))
+#define OFF0        (LEAF0 + 743 * sizeof (FcCharLeaf))
+#define NUM0        (OFF0 + 887 * sizeof (uintptr_t))
 #define SET(n)      (n * sizeof (FcLangCharSet) + offsetof (FcLangCharSet, charset))
 #define OFF(s,o)    (OFF0 + o * sizeof (uintptr_t) - SET(s))
 #define NUM(s,n)    (NUM0 + n * sizeof (FcChar16) - SET(s))
@@ -36,12 +36,12 @@
 #define fcLangCharSetIndicesInv (fcLangData.langIndicesInv)
 
 static const struct {
-    FcLangCharSet  langCharSets[281];
-    FcCharLeaf     leaves[742];
-    uintptr_t      leaf_offsets[886];
-    FcChar16       numbers[886];
-    FcChar16        langIndices[281];
-    FcChar16        langIndicesInv[281];
+    FcLangCharSet  langCharSets[282];
+    FcCharLeaf     leaves[743];
+    uintptr_t      leaf_offsets[887];
+    FcChar16       numbers[887];
+    FcChar16        langIndices[282];
+    FcChar16        langIndicesInv[282];
 } fcLangData = {
 {
     { "aa",  { FC_REF_CONSTANT, 1, OFF(0,0), NUM(0,0) } }, /* 0 */
@@ -272,59 +272,60 @@
     { "ss",  { FC_REF_CONSTANT, 1, OFF(225,27), NUM(225,27) } }, /* 225 */
     { "st",  { FC_REF_CONSTANT, 1, OFF(226,27), NUM(226,27) } }, /* 226 */
     { "su",  { FC_REF_CONSTANT, 1, OFF(227,207), NUM(227,207) } }, /* 227 */
-    { "sv",  { FC_REF_CONSTANT, 1, OFF(228,570), NUM(228,570) } }, /* 228 */
-    { "sw",  { FC_REF_CONSTANT, 1, OFF(229,27), NUM(229,27) } }, /* 229 */
-    { "syr",  { FC_REF_CONSTANT, 1, OFF(230,571), NUM(230,571) } }, /* 230 */
-    { "szl",  { FC_REF_CONSTANT, 2, OFF(231,572), NUM(231,572) } }, /* 231 */
-    { "ta",  { FC_REF_CONSTANT, 1, OFF(232,574), NUM(232,574) } }, /* 232 */
-    { "tcy",  { FC_REF_CONSTANT, 1, OFF(233,314), NUM(233,314) } }, /* 233 */
-    { "te",  { FC_REF_CONSTANT, 1, OFF(234,575), NUM(234,575) } }, /* 234 */
-    { "tg",  { FC_REF_CONSTANT, 1, OFF(235,576), NUM(235,576) } }, /* 235 */
-    { "th",  { FC_REF_CONSTANT, 1, OFF(236,577), NUM(236,577) } }, /* 236 */
-    { "the",  { FC_REF_CONSTANT, 1, OFF(237,13), NUM(237,13) } }, /* 237 */
-    { "ti-er",  { FC_REF_CONSTANT, 2, OFF(238,48), NUM(238,48) } }, /* 238 */
-    { "ti-et",  { FC_REF_CONSTANT, 2, OFF(239,555), NUM(239,555) } }, /* 239 */
-    { "tig",  { FC_REF_CONSTANT, 2, OFF(240,578), NUM(240,578) } }, /* 240 */
-    { "tk",  { FC_REF_CONSTANT, 2, OFF(241,580), NUM(241,580) } }, /* 241 */
-    { "tl",  { FC_REF_CONSTANT, 1, OFF(242,175), NUM(242,175) } }, /* 242 */
-    { "tn",  { FC_REF_CONSTANT, 2, OFF(243,507), NUM(243,507) } }, /* 243 */
-    { "to",  { FC_REF_CONSTANT, 2, OFF(244,559), NUM(244,559) } }, /* 244 */
-    { "tpi",  { FC_REF_CONSTANT, 1, OFF(245,164), NUM(245,164) } }, /* 245 */
-    { "tr",  { FC_REF_CONSTANT, 2, OFF(246,582), NUM(246,582) } }, /* 246 */
-    { "ts",  { FC_REF_CONSTANT, 1, OFF(247,27), NUM(247,27) } }, /* 247 */
-    { "tt",  { FC_REF_CONSTANT, 1, OFF(248,584), NUM(248,584) } }, /* 248 */
-    { "tw",  { FC_REF_CONSTANT, 5, OFF(249,5), NUM(249,5) } }, /* 249 */
-    { "ty",  { FC_REF_CONSTANT, 3, OFF(250,585), NUM(250,585) } }, /* 250 */
-    { "tyv",  { FC_REF_CONSTANT, 1, OFF(251,373), NUM(251,373) } }, /* 251 */
-    { "ug",  { FC_REF_CONSTANT, 1, OFF(252,588), NUM(252,588) } }, /* 252 */
-    { "uk",  { FC_REF_CONSTANT, 1, OFF(253,589), NUM(253,589) } }, /* 253 */
-    { "und-zmth",  { FC_REF_CONSTANT, 12, OFF(254,590), NUM(254,590) } }, /* 254 */
-    { "und-zsye",  { FC_REF_CONSTANT, 12, OFF(255,602), NUM(255,602) } }, /* 255 */
-    { "unm",  { FC_REF_CONSTANT, 1, OFF(256,164), NUM(256,164) } }, /* 256 */
-    { "ur",  { FC_REF_CONSTANT, 1, OFF(257,376), NUM(257,376) } }, /* 257 */
-    { "uz",  { FC_REF_CONSTANT, 1, OFF(258,27), NUM(258,27) } }, /* 258 */
-    { "ve",  { FC_REF_CONSTANT, 2, OFF(259,614), NUM(259,614) } }, /* 259 */
-    { "vi",  { FC_REF_CONSTANT, 4, OFF(260,616), NUM(260,616) } }, /* 260 */
-    { "vo",  { FC_REF_CONSTANT, 1, OFF(261,620), NUM(261,620) } }, /* 261 */
-    { "vot",  { FC_REF_CONSTANT, 2, OFF(262,621), NUM(262,621) } }, /* 262 */
-    { "wa",  { FC_REF_CONSTANT, 1, OFF(263,623), NUM(263,623) } }, /* 263 */
-    { "wae",  { FC_REF_CONSTANT, 1, OFF(264,156), NUM(264,156) } }, /* 264 */
-    { "wal",  { FC_REF_CONSTANT, 2, OFF(265,555), NUM(265,555) } }, /* 265 */
-    { "wen",  { FC_REF_CONSTANT, 2, OFF(266,624), NUM(266,624) } }, /* 266 */
-    { "wo",  { FC_REF_CONSTANT, 2, OFF(267,626), NUM(267,626) } }, /* 267 */
-    { "xh",  { FC_REF_CONSTANT, 1, OFF(268,27), NUM(268,27) } }, /* 268 */
-    { "yap",  { FC_REF_CONSTANT, 1, OFF(269,628), NUM(269,628) } }, /* 269 */
-    { "yi",  { FC_REF_CONSTANT, 1, OFF(270,197), NUM(270,197) } }, /* 270 */
-    { "yo",  { FC_REF_CONSTANT, 4, OFF(271,629), NUM(271,629) } }, /* 271 */
-    { "yue",  { FC_REF_CONSTANT, 171, OFF(272,633), NUM(272,633) } }, /* 272 */
-    { "yuw",  { FC_REF_CONSTANT, 1, OFF(273,164), NUM(273,164) } }, /* 273 */
-    { "za",  { FC_REF_CONSTANT, 1, OFF(274,27), NUM(274,27) } }, /* 274 */
-    { "zh-cn",  { FC_REF_CONSTANT, 82, OFF(275,804), NUM(275,804) } }, /* 275 */
-    { "zh-hk",  { FC_REF_CONSTANT, 171, OFF(276,633), NUM(276,633) } }, /* 276 */
-    { "zh-mo",  { FC_REF_CONSTANT, 171, OFF(277,633), NUM(277,633) } }, /* 277 */
-    { "zh-sg",  { FC_REF_CONSTANT, 82, OFF(278,804), NUM(278,804) } }, /* 278 */
-    { "zh-tw",  { FC_REF_CONSTANT, 83, OFF(279,56), NUM(279,56) } }, /* 279 */
-    { "zu",  { FC_REF_CONSTANT, 1, OFF(280,27), NUM(280,27) } }, /* 280 */
+    { "suz",  { FC_REF_CONSTANT, 1, OFF(228,570), NUM(228,570) } }, /* 228 */
+    { "sv",  { FC_REF_CONSTANT, 1, OFF(229,571), NUM(229,571) } }, /* 229 */
+    { "sw",  { FC_REF_CONSTANT, 1, OFF(230,27), NUM(230,27) } }, /* 230 */
+    { "syr",  { FC_REF_CONSTANT, 1, OFF(231,572), NUM(231,572) } }, /* 231 */
+    { "szl",  { FC_REF_CONSTANT, 2, OFF(232,573), NUM(232,573) } }, /* 232 */
+    { "ta",  { FC_REF_CONSTANT, 1, OFF(233,575), NUM(233,575) } }, /* 233 */
+    { "tcy",  { FC_REF_CONSTANT, 1, OFF(234,314), NUM(234,314) } }, /* 234 */
+    { "te",  { FC_REF_CONSTANT, 1, OFF(235,576), NUM(235,576) } }, /* 235 */
+    { "tg",  { FC_REF_CONSTANT, 1, OFF(236,577), NUM(236,577) } }, /* 236 */
+    { "th",  { FC_REF_CONSTANT, 1, OFF(237,578), NUM(237,578) } }, /* 237 */
+    { "the",  { FC_REF_CONSTANT, 1, OFF(238,13), NUM(238,13) } }, /* 238 */
+    { "ti-er",  { FC_REF_CONSTANT, 2, OFF(239,48), NUM(239,48) } }, /* 239 */
+    { "ti-et",  { FC_REF_CONSTANT, 2, OFF(240,555), NUM(240,555) } }, /* 240 */
+    { "tig",  { FC_REF_CONSTANT, 2, OFF(241,579), NUM(241,579) } }, /* 241 */
+    { "tk",  { FC_REF_CONSTANT, 2, OFF(242,581), NUM(242,581) } }, /* 242 */
+    { "tl",  { FC_REF_CONSTANT, 1, OFF(243,175), NUM(243,175) } }, /* 243 */
+    { "tn",  { FC_REF_CONSTANT, 2, OFF(244,507), NUM(244,507) } }, /* 244 */
+    { "to",  { FC_REF_CONSTANT, 2, OFF(245,559), NUM(245,559) } }, /* 245 */
+    { "tpi",  { FC_REF_CONSTANT, 1, OFF(246,164), NUM(246,164) } }, /* 246 */
+    { "tr",  { FC_REF_CONSTANT, 2, OFF(247,583), NUM(247,583) } }, /* 247 */
+    { "ts",  { FC_REF_CONSTANT, 1, OFF(248,27), NUM(248,27) } }, /* 248 */
+    { "tt",  { FC_REF_CONSTANT, 1, OFF(249,585), NUM(249,585) } }, /* 249 */
+    { "tw",  { FC_REF_CONSTANT, 5, OFF(250,5), NUM(250,5) } }, /* 250 */
+    { "ty",  { FC_REF_CONSTANT, 3, OFF(251,586), NUM(251,586) } }, /* 251 */
+    { "tyv",  { FC_REF_CONSTANT, 1, OFF(252,373), NUM(252,373) } }, /* 252 */
+    { "ug",  { FC_REF_CONSTANT, 1, OFF(253,589), NUM(253,589) } }, /* 253 */
+    { "uk",  { FC_REF_CONSTANT, 1, OFF(254,590), NUM(254,590) } }, /* 254 */
+    { "und-zmth",  { FC_REF_CONSTANT, 12, OFF(255,591), NUM(255,591) } }, /* 255 */
+    { "und-zsye",  { FC_REF_CONSTANT, 12, OFF(256,603), NUM(256,603) } }, /* 256 */
+    { "unm",  { FC_REF_CONSTANT, 1, OFF(257,164), NUM(257,164) } }, /* 257 */
+    { "ur",  { FC_REF_CONSTANT, 1, OFF(258,376), NUM(258,376) } }, /* 258 */
+    { "uz",  { FC_REF_CONSTANT, 1, OFF(259,27), NUM(259,27) } }, /* 259 */
+    { "ve",  { FC_REF_CONSTANT, 2, OFF(260,615), NUM(260,615) } }, /* 260 */
+    { "vi",  { FC_REF_CONSTANT, 4, OFF(261,617), NUM(261,617) } }, /* 261 */
+    { "vo",  { FC_REF_CONSTANT, 1, OFF(262,621), NUM(262,621) } }, /* 262 */
+    { "vot",  { FC_REF_CONSTANT, 2, OFF(263,622), NUM(263,622) } }, /* 263 */
+    { "wa",  { FC_REF_CONSTANT, 1, OFF(264,624), NUM(264,624) } }, /* 264 */
+    { "wae",  { FC_REF_CONSTANT, 1, OFF(265,156), NUM(265,156) } }, /* 265 */
+    { "wal",  { FC_REF_CONSTANT, 2, OFF(266,555), NUM(266,555) } }, /* 266 */
+    { "wen",  { FC_REF_CONSTANT, 2, OFF(267,625), NUM(267,625) } }, /* 267 */
+    { "wo",  { FC_REF_CONSTANT, 2, OFF(268,627), NUM(268,627) } }, /* 268 */
+    { "xh",  { FC_REF_CONSTANT, 1, OFF(269,27), NUM(269,27) } }, /* 269 */
+    { "yap",  { FC_REF_CONSTANT, 1, OFF(270,629), NUM(270,629) } }, /* 270 */
+    { "yi",  { FC_REF_CONSTANT, 1, OFF(271,197), NUM(271,197) } }, /* 271 */
+    { "yo",  { FC_REF_CONSTANT, 4, OFF(272,630), NUM(272,630) } }, /* 272 */
+    { "yue",  { FC_REF_CONSTANT, 171, OFF(273,634), NUM(273,634) } }, /* 273 */
+    { "yuw",  { FC_REF_CONSTANT, 1, OFF(274,164), NUM(274,164) } }, /* 274 */
+    { "za",  { FC_REF_CONSTANT, 1, OFF(275,27), NUM(275,27) } }, /* 275 */
+    { "zh-cn",  { FC_REF_CONSTANT, 82, OFF(276,805), NUM(276,805) } }, /* 276 */
+    { "zh-hk",  { FC_REF_CONSTANT, 171, OFF(277,634), NUM(277,634) } }, /* 277 */
+    { "zh-mo",  { FC_REF_CONSTANT, 171, OFF(278,634), NUM(278,634) } }, /* 278 */
+    { "zh-sg",  { FC_REF_CONSTANT, 82, OFF(279,805), NUM(279,805) } }, /* 279 */
+    { "zh-tw",  { FC_REF_CONSTANT, 83, OFF(280,56), NUM(280,56) } }, /* 280 */
+    { "zu",  { FC_REF_CONSTANT, 1, OFF(281,27), NUM(281,27) } }, /* 281 */
 },
 {
     { { /* 0 */
@@ -2080,1218 +2081,1222 @@
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
     { { /* 438 */
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0xffffffff, 0x03ff0003,
+    } },
+    { { /* 439 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x10400a33, 0x10400a33,
     } },
-    { { /* 439 */
+    { { /* 440 */
     0xffff0000, 0xffff1fff, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 440 */
+    { { /* 441 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x00380008, 0x00080000,
     } },
-    { { /* 441 */
+    { { /* 442 */
     0x030000f0, 0x00000000, 0x0c00501e, 0x1e004000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 442 */
+    { { /* 443 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0xd63dc7e8, 0xc3bfc718, 0x00803dc7, 0x00000000,
     } },
-    { { /* 443 */
+    { { /* 444 */
     0xfffddfee, 0xc3effdff, 0x00603ddf, 0x00000003,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 444 */
+    { { /* 445 */
     0xffff0002, 0xffffffff, 0x0002ffff, 0x00000000,
     0x0c0c0000, 0x00cc0000, 0x00000000, 0x0000c00c,
     } },
-    { { /* 445 */
+    { { /* 446 */
     0xfffffffe, 0x87ffffff, 0x00007fff, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 446 */
+    { { /* 447 */
     0xff7fff7f, 0xff01ff00, 0x00003d7f, 0xffff7fff,
     0x00ff0000, 0x003d7f7f, 0xff7f7f00, 0x00ff7f00,
     } },
-    { { /* 447 */
+    { { /* 448 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x30400090, 0x30400090,
     } },
-    { { /* 448 */
+    { { /* 449 */
     0x00000000, 0x00000000, 0xc0000180, 0x60000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 449 */
+    { { /* 450 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x18404084, 0x18404084,
     } },
-    { { /* 450 */
+    { { /* 451 */
     0xffff0002, 0xffffffff, 0x0002ffff, 0x00000000,
     0x00c00000, 0x0c00c00c, 0x03000000, 0x00000000,
     } },
-    { { /* 451 */
+    { { /* 452 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x00008000, 0x00008000,
     } },
-    { { /* 452 */
+    { { /* 453 */
     0x00000000, 0x041ed5c0, 0x0000077e, 0x40000000,
     0x01000040, 0x4000a000, 0x002109c0, 0x00000000,
     } },
-    { { /* 453 */
+    { { /* 454 */
     0xffff00d0, 0xffffffff, 0x00d0ffff, 0x00000000,
     0x00030000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 454 */
+    { { /* 455 */
     0x00000000, 0xffffff7b, 0x7fffffff, 0x7ffffffe,
     0x00000000, 0x80e310fe, 0x00800000, 0x00800000,
     } },
-    { { /* 455 */
+    { { /* 456 */
     0x00000000, 0x00020000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 456 */
+    { { /* 457 */
     0x00001500, 0x01000000, 0x00000000, 0x00000000,
     0xfffe0000, 0xfffe03db, 0x006003fb, 0x00030000,
     } },
-    { { /* 457 */
+    { { /* 458 */
     0x00400000, 0x00000047, 0x00800010, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000002,
     } },
-    { { /* 458 */
+    { { /* 459 */
     0x3f2fc004, 0x00000010, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 459 */
+    { { /* 460 */
     0xe3ffbfff, 0xfff007ff, 0x00000001, 0x00000000,
     0xfffff000, 0x0000003f, 0x0000e10f, 0x00000000,
     } },
-    { { /* 460 */
+    { { /* 461 */
     0x00000f00, 0x0000000c, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 461 */
+    { { /* 462 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000003, 0x00000000, 0x00000000,
     } },
-    { { /* 462 */
+    { { /* 463 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x000003c0,
     } },
-    { { /* 463 */
+    { { /* 464 */
     0xffffffff, 0xffffffff, 0xffdfffff, 0xffffffff,
     0xdfffffff, 0x00001e64, 0x00000000, 0x00000000,
     } },
-    { { /* 464 */
+    { { /* 465 */
     0x00000000, 0x78000000, 0x0001fc5f, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 465 */
+    { { /* 466 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000030, 0x00000000, 0x00000000,
     } },
-    { { /* 466 */
+    { { /* 467 */
     0x0c000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00091e00,
     } },
-    { { /* 467 */
+    { { /* 468 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x60000000,
     } },
-    { { /* 468 */
+    { { /* 469 */
     0x00300000, 0x00000000, 0x000fff00, 0x80000000,
     0x00080000, 0x60000c02, 0x00104030, 0x242c0400,
     } },
-    { { /* 469 */
+    { { /* 470 */
     0x00000c20, 0x00000100, 0x00b85000, 0x00000000,
     0x00e00000, 0x80010000, 0x00000000, 0x00000000,
     } },
-    { { /* 470 */
+    { { /* 471 */
     0x18000000, 0x00000000, 0x00210000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 471 */
+    { { /* 472 */
     0x00000010, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00008000, 0x00000000,
     } },
-    { { /* 472 */
+    { { /* 473 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x07fe4000, 0x00000000, 0x00000000, 0xffffffc0,
     } },
-    { { /* 473 */
+    { { /* 474 */
     0x04000002, 0x077c8000, 0x00030000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 474 */
+    { { /* 475 */
     0xffffffff, 0xffbf0001, 0xffffffff, 0x1fffffff,
     0x000fffff, 0xffffffff, 0x000007df, 0x0001ffff,
     } },
-    { { /* 475 */
+    { { /* 476 */
     0x00000000, 0x00000000, 0xfffffffd, 0xffffffff,
     0xffffffff, 0xffffffff, 0xffffffff, 0x1effffff,
     } },
-    { { /* 476 */
+    { { /* 477 */
     0xffffffff, 0x3fffffff, 0xffff0000, 0x000000ff,
     0x00000000, 0x00000000, 0x00000000, 0xf8000000,
     } },
-    { { /* 477 */
+    { { /* 478 */
     0x755dfffe, 0xffef2f3f, 0x0000ffe1, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 478 */
+    { { /* 479 */
     0x000c0000, 0x30000000, 0x00000c30, 0x00030000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 479 */
+    { { /* 480 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x263c370f, 0x263c370f,
     } },
-    { { /* 480 */
+    { { /* 481 */
     0x0003000c, 0x00000300, 0x00000000, 0x00000300,
     0x00000000, 0x00018003, 0x00000000, 0x00000000,
     } },
-    { { /* 481 */
+    { { /* 482 */
     0x0800024f, 0x00000008, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 482 */
+    { { /* 483 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0xffffffff, 0xffffffff, 0x03ffffff,
     } },
-    { { /* 483 */
-    0x00000000, 0x00000000, 0x077dfffe, 0x077dfffe,
-    0x00000000, 0x00000000, 0x10400010, 0x10400010,
-    } },
     { { /* 484 */
-    0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
+    0x00000000, 0x00000000, 0x077dfffe, 0x077dfffe,
     0x00000000, 0x00000000, 0x10400010, 0x10400010,
     } },
     { { /* 485 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
-    0x00000000, 0x00000000, 0x081047a4, 0x081047a4,
+    0x00000000, 0x00000000, 0x10400010, 0x10400010,
     } },
     { { /* 486 */
+    0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
+    0x00000000, 0x00000000, 0x081047a4, 0x081047a4,
+    } },
+    { { /* 487 */
     0x0c0030c0, 0x00000000, 0x0f30001e, 0x66000003,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 487 */
+    { { /* 488 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x000a0a09, 0x000a0a09,
     } },
-    { { /* 488 */
+    { { /* 489 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x00400810, 0x00400810,
     } },
-    { { /* 489 */
+    { { /* 490 */
     0x00000000, 0x00000000, 0x07fffffe, 0x07fffffe,
     0x00000000, 0x00000000, 0x0e3c770f, 0x0e3c770f,
     } },
-    { { /* 490 */
+    { { /* 491 */
     0x0c000000, 0x00000300, 0x00000018, 0x00000300,
     0x00000000, 0x00000000, 0x001fe000, 0x03000000,
     } },
-    { { /* 491 */
+    { { /* 492 */
     0x0000100f, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 492 */
+    { { /* 493 */
     0x00000000, 0xc0000000, 0x00000000, 0x0000000c,
     0x00000000, 0x33000000, 0x00003000, 0x00000000,
     } },
-    { { /* 493 */
+    { { /* 494 */
     0x00000080, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 494 */
+    { { /* 495 */
     0x00000000, 0x00000000, 0x00001000, 0x64080010,
     0x00480000, 0x10000020, 0x80000102, 0x08000010,
     } },
-    { { /* 495 */
+    { { /* 496 */
     0x00000040, 0x40000000, 0x00020000, 0x01852002,
     0x00800010, 0x80002022, 0x084444a2, 0x480e0000,
     } },
-    { { /* 496 */
+    { { /* 497 */
     0x04000200, 0x02202008, 0x80004380, 0x04000000,
     0x00000002, 0x12231420, 0x2058003a, 0x00200060,
     } },
-    { { /* 497 */
+    { { /* 498 */
     0x10002508, 0x040d0028, 0x00000009, 0x00008004,
     0x00800000, 0x42000001, 0x00000000, 0x09040000,
     } },
-    { { /* 498 */
+    { { /* 499 */
     0x02008000, 0x01402001, 0x00000000, 0x00000008,
     0x00000000, 0x00000001, 0x00021008, 0x04000000,
     } },
-    { { /* 499 */
+    { { /* 500 */
     0x00100100, 0x80040080, 0x00002000, 0x00000008,
     0x08040601, 0x01000012, 0x10000000, 0x49001024,
     } },
-    { { /* 500 */
+    { { /* 501 */
     0x0180004a, 0x00100600, 0x50840800, 0x000000c0,
     0x00800000, 0x20000800, 0x40000000, 0x08050000,
     } },
-    { { /* 501 */
+    { { /* 502 */
     0x02004000, 0x02000804, 0x01000004, 0x18060001,
     0x02400001, 0x40000002, 0x20800014, 0x000c1000,
     } },
-    { { /* 502 */
+    { { /* 503 */
     0x00222000, 0x00000000, 0x00100000, 0x00000000,
     0x00000000, 0x00000000, 0x10422800, 0x00000800,
     } },
-    { { /* 503 */
+    { { /* 504 */
     0x20080000, 0x00040000, 0x80025040, 0x20208604,
     0x00028020, 0x80102020, 0x080820c0, 0x10880800,
     } },
-    { { /* 504 */
+    { { /* 505 */
     0x00000000, 0x00000000, 0x00200109, 0x00100000,
     0x00000000, 0x81022700, 0x40c21404, 0x84010882,
     } },
-    { { /* 505 */
+    { { /* 506 */
     0x00004010, 0x00000000, 0x03000000, 0x00000008,
     0x00080000, 0x00000000, 0x10800001, 0x06002020,
     } },
-    { { /* 506 */
+    { { /* 507 */
     0x00000010, 0x02000000, 0x00880020, 0x00008424,
     0x00000000, 0x88000000, 0x81000100, 0x04000000,
     } },
-    { { /* 507 */
+    { { /* 508 */
     0x00004218, 0x00040000, 0x00000000, 0x80005080,
     0x00010000, 0x00040000, 0x08008000, 0x02008000,
     } },
-    { { /* 508 */
+    { { /* 509 */
     0x00020000, 0x00000000, 0x00000001, 0x04000401,
     0x00100000, 0x12200004, 0x00000000, 0x18100000,
     } },
-    { { /* 509 */
+    { { /* 510 */
     0x00000000, 0x00000800, 0x00000000, 0x00004000,
     0x00800000, 0x04000000, 0x82000002, 0x00042000,
     } },
-    { { /* 510 */
+    { { /* 511 */
     0x00080006, 0x00000000, 0x00000000, 0x04000000,
     0x80008000, 0x00810001, 0xa0000000, 0x00100410,
     } },
-    { { /* 511 */
+    { { /* 512 */
     0x00400218, 0x88084080, 0x00260008, 0x00800404,
     0x00000020, 0x00000000, 0x00000000, 0x00000200,
     } },
-    { { /* 512 */
+    { { /* 513 */
     0x00a08048, 0x00000000, 0x08000000, 0x04000000,
     0x00000000, 0x00000000, 0x00018000, 0x00200000,
     } },
-    { { /* 513 */
+    { { /* 514 */
     0x01000000, 0x00000000, 0x00000000, 0x10000000,
     0x00000000, 0x00000000, 0x00200000, 0x00102000,
     } },
-    { { /* 514 */
+    { { /* 515 */
     0x00000801, 0x00000000, 0x00000000, 0x00020000,
     0x08000000, 0x00002000, 0x20010000, 0x04002000,
     } },
-    { { /* 515 */
+    { { /* 516 */
     0x40000040, 0x50202400, 0x000a0020, 0x00040420,
     0x00000200, 0x00000080, 0x80000000, 0x00000020,
     } },
-    { { /* 516 */
+    { { /* 517 */
     0x20008000, 0x00200010, 0x00000000, 0x00000000,
     0x00400000, 0x01100000, 0x00020000, 0x80000010,
     } },
-    { { /* 517 */
+    { { /* 518 */
     0x02000000, 0x00801000, 0x00000000, 0x48058000,
     0x20c94000, 0x60000000, 0x00000001, 0x00000000,
     } },
-    { { /* 518 */
+    { { /* 519 */
     0x00004090, 0x48000000, 0x08000000, 0x28802000,
     0x00000002, 0x00014000, 0x00002000, 0x00002002,
     } },
-    { { /* 519 */
+    { { /* 520 */
     0x00010200, 0x00100000, 0x00000000, 0x00800000,
     0x10020000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 520 */
+    { { /* 521 */
     0x00000010, 0x00000402, 0x0c000000, 0x01000400,
     0x01000021, 0x00000000, 0x00004000, 0x00004000,
     } },
-    { { /* 521 */
+    { { /* 522 */
     0x00000000, 0x00800000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x02000020,
     } },
-    { { /* 522 */
+    { { /* 523 */
     0x00000100, 0x08000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00002000, 0x00000000,
     } },
-    { { /* 523 */
+    { { /* 524 */
     0x00006000, 0x00000000, 0x00000000, 0x00000400,
     0x04000040, 0x003c0180, 0x00000200, 0x00102000,
     } },
-    { { /* 524 */
+    { { /* 525 */
     0x00000800, 0x101000c0, 0x00800000, 0x00000000,
     0x00008000, 0x02200000, 0x00020020, 0x00000000,
     } },
-    { { /* 525 */
+    { { /* 526 */
     0x00000000, 0x01000000, 0x00000000, 0x20100000,
     0x00080000, 0x00000141, 0x02001002, 0x40400001,
     } },
-    { { /* 526 */
+    { { /* 527 */
     0x00580000, 0x00000002, 0x00003000, 0x00002400,
     0x00988000, 0x00040010, 0x00002800, 0x00000008,
     } },
-    { { /* 527 */
+    { { /* 528 */
     0x40080004, 0x00000020, 0x20080000, 0x02060a00,
     0x00010040, 0x14010200, 0x40800000, 0x08031000,
     } },
-    { { /* 528 */
+    { { /* 529 */
     0x40020020, 0x0000202c, 0x2014a008, 0x00000000,
     0x80040200, 0x82020012, 0x00400000, 0x20000000,
     } },
-    { { /* 529 */
+    { { /* 530 */
     0x00000000, 0x00000000, 0x00000004, 0x04000000,
     0x00000000, 0x00000000, 0x40800100, 0x00000000,
     } },
-    { { /* 530 */
+    { { /* 531 */
     0x00000008, 0x04000040, 0x00000001, 0x000c0200,
     0x00000000, 0x08000400, 0x00000000, 0x080c0001,
     } },
-    { { /* 531 */
+    { { /* 532 */
     0x00000400, 0x00000000, 0x00000000, 0x00200000,
     0x80000000, 0x00001000, 0x00000200, 0x01000800,
     } },
-    { { /* 532 */
+    { { /* 533 */
     0x00000000, 0x00000800, 0x00000000, 0x40000000,
     0x00000000, 0x00000000, 0x00000000, 0x04040000,
     } },
-    { { /* 533 */
+    { { /* 534 */
     0x00000000, 0x00000000, 0x00000040, 0x00002000,
     0xa0000000, 0x00000000, 0x08000008, 0x00080000,
     } },
-    { { /* 534 */
+    { { /* 535 */
     0x00000020, 0x00000000, 0x40000400, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00008000,
     } },
-    { { /* 535 */
+    { { /* 536 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000800, 0x00000000, 0x00000000, 0x00200000,
     } },
-    { { /* 536 */
+    { { /* 537 */
     0x00000000, 0x00000000, 0x00000000, 0x04000000,
     0x00000008, 0x00000000, 0x00010000, 0x1b000000,
     } },
-    { { /* 537 */
+    { { /* 538 */
     0x00007000, 0x00000000, 0x10000000, 0x00000000,
     0x00000000, 0x00000080, 0x80000000, 0x00000000,
     } },
-    { { /* 538 */
+    { { /* 539 */
     0x00000000, 0x00020000, 0x00000000, 0x00200000,
     0x40000000, 0x00000010, 0x00800000, 0x00000008,
     } },
-    { { /* 539 */
+    { { /* 540 */
     0x00000000, 0x00000000, 0x02000000, 0x20000010,
     0x00000080, 0x00000000, 0x00010000, 0x00000000,
     } },
-    { { /* 540 */
+    { { /* 541 */
     0x00000000, 0x02000000, 0x00000000, 0x00000000,
     0x20000000, 0x00000040, 0x00200028, 0x00000000,
     } },
-    { { /* 541 */
+    { { /* 542 */
     0x00000000, 0x00020000, 0x00000000, 0x02000000,
     0x00000000, 0x02000000, 0x40020000, 0x51000040,
     } },
-    { { /* 542 */
+    { { /* 543 */
     0x00000080, 0x04040000, 0x00000000, 0x10000000,
     0x00022000, 0x00100000, 0x20000000, 0x00000082,
     } },
-    { { /* 543 */
+    { { /* 544 */
     0x40000000, 0x00010000, 0x00002000, 0x00000000,
     0x00000240, 0x00000000, 0x00000000, 0x00000008,
     } },
-    { { /* 544 */
+    { { /* 545 */
     0x00000000, 0x00010000, 0x00000810, 0x00080880,
     0x00004000, 0x00000000, 0x00000000, 0x00020000,
     } },
-    { { /* 545 */
+    { { /* 546 */
     0x00000000, 0x00400020, 0x00000000, 0x00000082,
     0x00000000, 0x00020001, 0x00000000, 0x00000000,
     } },
-    { { /* 546 */
+    { { /* 547 */
     0x40000018, 0x00000004, 0x00000000, 0x00000000,
     0x01000000, 0x00400000, 0x00000000, 0x00000000,
     } },
-    { { /* 547 */
+    { { /* 548 */
     0x00000001, 0x00400000, 0x00000000, 0x00080002,
     0x00000400, 0x00040000, 0x00000000, 0x00000000,
     } },
-    { { /* 548 */
+    { { /* 549 */
     0x00000800, 0x00000800, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000100, 0x00000000,
     } },
-    { { /* 549 */
+    { { /* 550 */
     0x00000000, 0x00200000, 0x00000000, 0x04108000,
     0x00000000, 0x00000000, 0x00000000, 0x00000002,
     } },
-    { { /* 550 */
+    { { /* 551 */
     0x00000000, 0x02800000, 0x04000000, 0x00000000,
     0x00000000, 0x00000004, 0x00000000, 0x00000400,
     } },
-    { { /* 551 */
+    { { /* 552 */
     0x00000000, 0x00000000, 0x10000000, 0x00040000,
     0x00400000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 552 */
+    { { /* 553 */
     0x00200000, 0x00000200, 0x00000000, 0x10000000,
     0x00000000, 0x00000000, 0x2a000000, 0x00000000,
     } },
-    { { /* 553 */
+    { { /* 554 */
     0x00400000, 0x00000000, 0x00400000, 0x00000000,
     0x00000002, 0x40000000, 0x00000000, 0x00400000,
     } },
-    { { /* 554 */
+    { { /* 555 */
     0x40000000, 0x00001000, 0x00000000, 0x00000000,
     0x00000202, 0x02000000, 0x80000000, 0x00020000,
     } },
-    { { /* 555 */
+    { { /* 556 */
     0x00000020, 0x00000800, 0x00020421, 0x00020000,
     0x00000000, 0x00000000, 0x00000000, 0x00400000,
     } },
-    { { /* 556 */
+    { { /* 557 */
     0x00200000, 0x00000000, 0x00000001, 0x00000000,
     0x00000084, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 557 */
+    { { /* 558 */
     0x00000000, 0x00004400, 0x00000002, 0x00100000,
     0x00000000, 0x00000000, 0x00008200, 0x00000000,
     } },
-    { { /* 558 */
+    { { /* 559 */
     0x00000000, 0x12000000, 0x00000100, 0x00000001,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 559 */
+    { { /* 560 */
     0x00000020, 0x08100000, 0x000a0400, 0x00000081,
     0x00006000, 0x00120000, 0x00000000, 0x00000000,
     } },
-    { { /* 560 */
+    { { /* 561 */
     0x00000004, 0x08000000, 0x00004000, 0x044000c0,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 561 */
+    { { /* 562 */
     0x40001000, 0x00000000, 0x01000001, 0x05000000,
     0x00080000, 0x02000000, 0x00000800, 0x00000000,
     } },
-    { { /* 562 */
+    { { /* 563 */
     0x00000100, 0x00000000, 0x00000000, 0x00000000,
     0x00002002, 0x01020000, 0x00800000, 0x00000000,
     } },
-    { { /* 563 */
+    { { /* 564 */
     0x00000040, 0x00004000, 0x01000000, 0x00000004,
     0x00020000, 0x00000000, 0x00000010, 0x00000000,
     } },
-    { { /* 564 */
+    { { /* 565 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00080000, 0x00010000, 0x30000300, 0x00000400,
     } },
-    { { /* 565 */
+    { { /* 566 */
     0x00000800, 0x02000000, 0x00000000, 0x00008000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 566 */
+    { { /* 567 */
     0x00200000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x000040c0, 0x00002200, 0x12002000,
     } },
-    { { /* 567 */
+    { { /* 568 */
     0x00000000, 0x00000020, 0x20000000, 0x00000000,
     0x00000200, 0x00080800, 0x1000a000, 0x00000000,
     } },
-    { { /* 568 */
+    { { /* 569 */
     0x00000000, 0x00000000, 0x00000000, 0x00004000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 569 */
+    { { /* 570 */
     0x00000000, 0x00000000, 0x00004280, 0x01000000,
     0x00800000, 0x00000008, 0x00000000, 0x00000000,
     } },
-    { { /* 570 */
+    { { /* 571 */
     0x00000000, 0x00000000, 0x00000000, 0x00000002,
     0x00000000, 0x20400000, 0x00000040, 0x00000000,
     } },
-    { { /* 571 */
+    { { /* 572 */
     0x00800080, 0x00800000, 0x00000000, 0x00000000,
     0x00000000, 0x00400020, 0x00000000, 0x00008000,
     } },
-    { { /* 572 */
+    { { /* 573 */
     0x01000000, 0x00000040, 0x00000000, 0x00400000,
     0x00000000, 0x00000440, 0x00000000, 0x00800000,
     } },
-    { { /* 573 */
+    { { /* 574 */
     0x01000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00080000, 0x00000000,
     } },
-    { { /* 574 */
+    { { /* 575 */
     0x01000000, 0x00000001, 0x00000000, 0x00020000,
     0x00000000, 0x20002000, 0x00000000, 0x00000004,
     } },
-    { { /* 575 */
+    { { /* 576 */
     0x00000008, 0x00100000, 0x00000000, 0x00010000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 576 */
+    { { /* 577 */
     0x00000004, 0x00008000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00008000,
     } },
-    { { /* 577 */
+    { { /* 578 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000040, 0x00000000, 0x00004000, 0x00000000,
     } },
-    { { /* 578 */
+    { { /* 579 */
     0x00000010, 0x00002000, 0x40000040, 0x00000000,
     0x10000000, 0x00000000, 0x00008080, 0x00000000,
     } },
-    { { /* 579 */
+    { { /* 580 */
     0x00000000, 0x00000000, 0x00000080, 0x00000000,
     0x00100080, 0x000000a0, 0x00000000, 0x00000000,
     } },
-    { { /* 580 */
+    { { /* 581 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00100000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 581 */
+    { { /* 582 */
     0x00000000, 0x00000000, 0x00001000, 0x00000000,
     0x0001000a, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 582 */
+    { { /* 583 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x08002000, 0x00000000,
     } },
-    { { /* 583 */
+    { { /* 584 */
     0x00000808, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 584 */
+    { { /* 585 */
     0x00004000, 0x00002400, 0x00008000, 0x40000000,
     0x00000001, 0x00002000, 0x04000000, 0x00040004,
     } },
-    { { /* 585 */
+    { { /* 586 */
     0x00000000, 0x00002000, 0x00000000, 0x00000000,
     0x00000000, 0x1c200000, 0x00000000, 0x02000000,
     } },
-    { { /* 586 */
+    { { /* 587 */
     0x00000000, 0x00080000, 0x00400000, 0x00000002,
     0x00000000, 0x00000100, 0x00000000, 0x00000000,
     } },
-    { { /* 587 */
+    { { /* 588 */
     0x00000000, 0x00000000, 0x00000000, 0x00400000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 588 */
+    { { /* 589 */
     0x00004100, 0x00000400, 0x20200010, 0x00004004,
     0x00000000, 0x42000000, 0x00000000, 0x00000000,
     } },
-    { { /* 589 */
+    { { /* 590 */
     0x00000080, 0x00000000, 0x00000121, 0x00000200,
     0x000000b0, 0x80002000, 0x00000000, 0x00010000,
     } },
-    { { /* 590 */
+    { { /* 591 */
     0x00000010, 0x000000c0, 0x08100000, 0x00000020,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 591 */
+    { { /* 592 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x02000000, 0x00000404, 0x00000000, 0x00000000,
     } },
-    { { /* 592 */
+    { { /* 593 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00400000, 0x00000008, 0x00000000, 0x00000000,
     } },
-    { { /* 593 */
+    { { /* 594 */
     0x00000000, 0x00000002, 0x00020000, 0x00002000,
     0x00000000, 0x00000000, 0x00000000, 0x00204000,
     } },
-    { { /* 594 */
+    { { /* 595 */
     0x00000000, 0x00100000, 0x00000000, 0x00000000,
     0x00000000, 0x00800000, 0x00000100, 0x00000001,
     } },
-    { { /* 595 */
+    { { /* 596 */
     0x10000000, 0x01000000, 0x00002400, 0x00000004,
     0x00000000, 0x00000000, 0x00000020, 0x00000002,
     } },
-    { { /* 596 */
+    { { /* 597 */
     0x00010000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 597 */
+    { { /* 598 */
     0x00000000, 0x00002400, 0x00000000, 0x00000000,
     0x00004802, 0x00000000, 0x00000000, 0x80022000,
     } },
-    { { /* 598 */
+    { { /* 599 */
     0x00001004, 0x04208000, 0x20000020, 0x00040000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 599 */
+    { { /* 600 */
     0x00000000, 0x00100000, 0x40010000, 0x00000000,
     0x00080000, 0x00000000, 0x00100211, 0x00000000,
     } },
-    { { /* 600 */
+    { { /* 601 */
     0x00001400, 0x00000000, 0x00000000, 0x00000000,
     0x00610000, 0x80008c00, 0x00000000, 0x00000000,
     } },
-    { { /* 601 */
+    { { /* 602 */
     0x00000100, 0x00000040, 0x00000000, 0x00000004,
     0x00004000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 602 */
+    { { /* 603 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000400, 0x00000000,
     } },
-    { { /* 603 */
+    { { /* 604 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000210, 0x00000000, 0x00000000,
     } },
-    { { /* 604 */
+    { { /* 605 */
     0x00000000, 0x00000020, 0x00000002, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 605 */
+    { { /* 606 */
     0x00004000, 0x00000000, 0x00000000, 0x02000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 606 */
+    { { /* 607 */
     0x00000000, 0x00000000, 0x00080002, 0x01000020,
     0x00400000, 0x00200000, 0x00008000, 0x00000000,
     } },
-    { { /* 607 */
+    { { /* 608 */
     0x00000000, 0x00020000, 0x00000000, 0xc0020000,
     0x10000000, 0x00000080, 0x00000000, 0x00000000,
     } },
-    { { /* 608 */
+    { { /* 609 */
     0x00000210, 0x00000000, 0x00001000, 0x04480000,
     0x20000000, 0x00000004, 0x00800000, 0x02000000,
     } },
-    { { /* 609 */
+    { { /* 610 */
     0x00000000, 0x08006000, 0x00001000, 0x00000000,
     0x00000000, 0x00100000, 0x00000000, 0x00000400,
     } },
-    { { /* 610 */
+    { { /* 611 */
     0x00100000, 0x00000000, 0x10000000, 0x08608000,
     0x00000000, 0x00000000, 0x00080002, 0x00000000,
     } },
-    { { /* 611 */
+    { { /* 612 */
     0x00000000, 0x20000000, 0x00008020, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 612 */
+    { { /* 613 */
     0x00000000, 0x00000000, 0x00000000, 0x10000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 613 */
+    { { /* 614 */
     0x00000000, 0x00100000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 614 */
+    { { /* 615 */
     0x00000000, 0x00000400, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 615 */
+    { { /* 616 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x02000000,
     } },
-    { { /* 616 */
+    { { /* 617 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000080, 0x00000000,
     } },
-    { { /* 617 */
+    { { /* 618 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000002, 0x00000000, 0x00000000,
     } },
-    { { /* 618 */
+    { { /* 619 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00008000, 0x00000000,
     } },
-    { { /* 619 */
+    { { /* 620 */
     0x00000000, 0x00000000, 0x00000008, 0x00000000,
     0x00000000, 0x00000000, 0x00000400, 0x00000000,
     } },
-    { { /* 620 */
+    { { /* 621 */
     0x00000000, 0x00000000, 0x00220000, 0x00000004,
     0x00000000, 0x00040000, 0x00000004, 0x00000000,
     } },
-    { { /* 621 */
+    { { /* 622 */
     0x00000000, 0x00000000, 0x00001000, 0x00000080,
     0x00002000, 0x00000000, 0x00000000, 0x00004000,
     } },
-    { { /* 622 */
+    { { /* 623 */
     0x00000000, 0x00000000, 0x00000000, 0x00100000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 623 */
-    0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00200000, 0x00000000, 0x00000000, 0x00000000,
-    } },
     { { /* 624 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00000000, 0x04000000, 0x00000000, 0x00000000,
+    0x00200000, 0x00000000, 0x00000000, 0x00000000,
     } },
     { { /* 625 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00000200, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x04000000, 0x00000000, 0x00000000,
     } },
     { { /* 626 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00000001, 0x00000000, 0x00000000, 0x00000000,
+    0x00000200, 0x00000000, 0x00000000, 0x00000000,
     } },
     { { /* 627 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00000000, 0x00000000, 0x00080000, 0x00000000,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000,
     } },
     { { /* 628 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00000000, 0x01000000, 0x00000000, 0x00000400,
+    0x00000000, 0x00000000, 0x00080000, 0x00000000,
     } },
     { { /* 629 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
-    0x00000000, 0x00000080, 0x00000000, 0x00000000,
+    0x00000000, 0x01000000, 0x00000000, 0x00000400,
     } },
     { { /* 630 */
+    0x00000000, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000080, 0x00000000, 0x00000000,
+    } },
+    { { /* 631 */
     0x00000000, 0x00000800, 0x00000100, 0x40000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 631 */
+    { { /* 632 */
     0x00000000, 0x00200000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 632 */
+    { { /* 633 */
     0x00000000, 0x00000000, 0x01000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 633 */
+    { { /* 634 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x04000000, 0x00000000,
     } },
-    { { /* 634 */
+    { { /* 635 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00001000, 0x00000000,
     } },
-    { { /* 635 */
+    { { /* 636 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000400, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 636 */
+    { { /* 637 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x04040000,
     } },
-    { { /* 637 */
+    { { /* 638 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000020, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 638 */
+    { { /* 639 */
     0x00000000, 0x00000000, 0x00800000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 639 */
+    { { /* 640 */
     0x00000000, 0x00200000, 0x40000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 640 */
+    { { /* 641 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x20000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 641 */
+    { { /* 642 */
     0x00000000, 0x00000000, 0x00000000, 0x04000000,
     0x00000000, 0x00000001, 0x00000000, 0x00000000,
     } },
-    { { /* 642 */
+    { { /* 643 */
     0x00000000, 0x40000000, 0x02000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 643 */
+    { { /* 644 */
     0x00000000, 0x00000000, 0x00000000, 0x00080000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 644 */
+    { { /* 645 */
     0x00000000, 0x00000010, 0x00000000, 0x00000000,
     0x00000000, 0x20000000, 0x00000000, 0x00000000,
     } },
-    { { /* 645 */
+    { { /* 646 */
     0x00000000, 0x00000000, 0x20000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 646 */
+    { { /* 647 */
     0x00000080, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000004,
     } },
-    { { /* 647 */
+    { { /* 648 */
     0x00000000, 0x00000000, 0x00000000, 0x00002000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 648 */
+    { { /* 649 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x10000001, 0x00000000,
     } },
-    { { /* 649 */
+    { { /* 650 */
     0x00008000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 650 */
+    { { /* 651 */
     0x00000000, 0x00000000, 0x00004040, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 651 */
+    { { /* 652 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00042400, 0x00000000,
     } },
-    { { /* 652 */
+    { { /* 653 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x02000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 653 */
+    { { /* 654 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000080,
     } },
-    { { /* 654 */
+    { { /* 655 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000020,
     } },
-    { { /* 655 */
+    { { /* 656 */
     0x00000000, 0x00000001, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 656 */
+    { { /* 657 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00020000, 0x00000000,
     } },
-    { { /* 657 */
+    { { /* 658 */
     0x00000000, 0x00000000, 0x00002000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 658 */
+    { { /* 659 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x01000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 659 */
+    { { /* 660 */
     0x00000000, 0x00040000, 0x08000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 660 */
+    { { /* 661 */
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     0x00000000, 0x00000000, 0x00000280, 0x00000000,
     } },
-    { { /* 661 */
+    { { /* 662 */
     0x7f7b7f8b, 0xef553db4, 0xf35dfba8, 0x400b0243,
     0x8d3efb40, 0x8c2c7bf7, 0xe3fa6eff, 0xa8ed1d3a,
     } },
-    { { /* 662 */
+    { { /* 663 */
     0xcf83e602, 0x35558cf5, 0xffabe048, 0xd85992b9,
     0x2892ab18, 0x8020d7e9, 0xf583c438, 0x450ae74a,
     } },
-    { { /* 663 */
+    { { /* 664 */
     0x9714b000, 0x54007762, 0x1420d188, 0xc8c01020,
     0x00002121, 0x0c0413a8, 0x04408000, 0x082870c0,
     } },
-    { { /* 664 */
+    { { /* 665 */
     0x000408c0, 0x80000002, 0x14722b7b, 0x3bfb7924,
     0x1ae43327, 0x38ef9835, 0x28029ad1, 0xbf69a813,
     } },
-    { { /* 665 */
+    { { /* 666 */
     0x2fc665cf, 0xafc96b11, 0x5053340f, 0xa00486a2,
     0xe8090106, 0xc00e3f0f, 0x81450a88, 0xc6010010,
     } },
-    { { /* 666 */
+    { { /* 667 */
     0x26e1a161, 0xce00444b, 0xd4eec7aa, 0x85bbcadf,
     0xa5203a74, 0x8840436c, 0x8bd23f06, 0x3befff79,
     } },
-    { { /* 667 */
+    { { /* 668 */
     0xe8eff75a, 0x5b36fbcb, 0x1bfd0d49, 0x39ee0154,
     0x2e75d855, 0xa91abfd8, 0xf6bff3d7, 0xb40c67e0,
     } },
-    { { /* 668 */
+    { { /* 669 */
     0x081382c2, 0xd08bd49d, 0x1061065a, 0x59e074f2,
     0xb3128f9f, 0x6aaa0080, 0xb05e3230, 0x60ac9d7a,
     } },
-    { { /* 669 */
+    { { /* 670 */
     0xc900d303, 0x8a563098, 0x13907000, 0x18421f14,
     0x0008c060, 0x10808008, 0xec900400, 0xe6332817,
     } },
-    { { /* 670 */
+    { { /* 671 */
     0x90000758, 0x4e09f708, 0xfc83f485, 0x18c8af53,
     0x080c187c, 0x01146adf, 0xa734c80c, 0x2710a011,
     } },
-    { { /* 671 */
+    { { /* 672 */
     0x422228c5, 0x00210413, 0x41123010, 0x40001820,
     0xc60c022b, 0x10000300, 0x00220022, 0x02495810,
     } },
-    { { /* 672 */
+    { { /* 673 */
     0x9670a094, 0x1792eeb0, 0x05f2cb96, 0x23580025,
     0x42cc25de, 0x4a04cf38, 0x359f0c40, 0x8a001128,
     } },
-    { { /* 673 */
+    { { /* 674 */
     0x910a13fa, 0x10560229, 0x04200641, 0x84f00484,
     0x0c040000, 0x412c0400, 0x11541206, 0x00020a4b,
     } },
-    { { /* 674 */
+    { { /* 675 */
     0x00c00200, 0x00940000, 0xbfbb0001, 0x242b167c,
     0x7fa89bbb, 0xe3790c7f, 0xe00d10f4, 0x9f014132,
     } },
-    { { /* 675 */
+    { { /* 676 */
     0x35728652, 0xff1210b4, 0x4223cf27, 0x8602c06b,
     0x1fd33106, 0xa1aa3a0c, 0x02040812, 0x08012572,
     } },
-    { { /* 676 */
+    { { /* 677 */
     0x485040cc, 0x601062d0, 0x29001c80, 0x00109a00,
     0x22000004, 0x00800000, 0x68002020, 0x609ecbe6,
     } },
-    { { /* 677 */
+    { { /* 678 */
     0x3f73916e, 0x398260c0, 0x48301034, 0xbd5c0006,
     0xd6fb8cd1, 0x43e820e1, 0x084e0600, 0xc4d00500,
     } },
-    { { /* 678 */
+    { { /* 679 */
     0x89aa8d1f, 0x1602a6e1, 0x21ed0001, 0x1a8b3656,
     0x13a51fb7, 0x30a06502, 0x23c7b278, 0xe9226c93,
     } },
-    { { /* 679 */
+    { { /* 680 */
     0x3a74e47f, 0x98208fe3, 0x2625280e, 0xbf49bf9c,
     0xac543218, 0x1916b949, 0xb5220c60, 0x0659fbc1,
     } },
-    { { /* 680 */
+    { { /* 681 */
     0x8420e343, 0x800008d9, 0x20225500, 0x00a10184,
     0x20104800, 0x40801380, 0x00160d04, 0x80200040,
     } },
-    { { /* 681 */
+    { { /* 682 */
     0x8de7fd40, 0xe0985436, 0x091e7b8b, 0xd249fec8,
     0x8dee0611, 0xba221937, 0x9fdd77f4, 0xf0daf3ec,
     } },
-    { { /* 682 */
+    { { /* 683 */
     0xec424386, 0x26048d3f, 0xc021fa6c, 0x0cc2628e,
     0x0145d785, 0x559977ad, 0x4045e250, 0xa154260b,
     } },
-    { { /* 683 */
+    { { /* 684 */
     0x58199827, 0xa4103443, 0x411405f2, 0x07002280,
     0x426600b4, 0x15a17210, 0x41856025, 0x00000054,
     } },
-    { { /* 684 */
+    { { /* 685 */
     0x01040201, 0xcb70c820, 0x6a629320, 0x0095184c,
     0x9a8b1880, 0x3201aab2, 0x00c4d87a, 0x04c3f3e5,
     } },
-    { { /* 685 */
+    { { /* 686 */
     0xa238d44d, 0x5072a1a1, 0x84fc980a, 0x44d1c152,
     0x20c21094, 0x42104180, 0x3a000000, 0xd29d0240,
     } },
-    { { /* 686 */
+    { { /* 687 */
     0xa8b12f01, 0x2432bd40, 0xd04bd34d, 0xd0ada723,
     0x75a10a92, 0x01e9adac, 0x771f801a, 0xa01b9225,
     } },
-    { { /* 687 */
+    { { /* 688 */
     0x20cadfa1, 0x738c0602, 0x003b577f, 0x00d00bff,
     0x0088806a, 0x0029a1c4, 0x05242a05, 0x16234009,
     } },
-    { { /* 688 */
+    { { /* 689 */
     0x80056822, 0xa2112011, 0x64900004, 0x13824849,
     0x193023d5, 0x08922980, 0x88115402, 0xa0042001,
     } },
-    { { /* 689 */
+    { { /* 690 */
     0x81800400, 0x60228502, 0x0b010090, 0x12020022,
     0x00834011, 0x00001a01, 0x00000000, 0x00000000,
     } },
-    { { /* 690 */
+    { { /* 691 */
     0x00000000, 0x4684009f, 0x020012c8, 0x1a0004fc,
     0x0c4c2ede, 0x80b80402, 0x0afca826, 0x22288c02,
     } },
-    { { /* 691 */
+    { { /* 692 */
     0x8f7ba0e0, 0x2135c7d6, 0xf8b106c7, 0x62550713,
     0x8a19936e, 0xfb0e6efa, 0x48f91630, 0x7debcd2f,
     } },
-    { { /* 692 */
+    { { /* 693 */
     0x4e845892, 0x7a2e4ca0, 0x561eedea, 0x1190c649,
     0xe83a5324, 0x8124cfdb, 0x634218f1, 0x1a8a5853,
     } },
-    { { /* 693 */
+    { { /* 694 */
     0x24d37420, 0x0514aa3b, 0x89586018, 0xc0004800,
     0x91018268, 0x2cd684a4, 0xc4ba8886, 0x02100377,
     } },
-    { { /* 694 */
+    { { /* 695 */
     0x00388244, 0x404aae11, 0x510028c0, 0x15146044,
     0x10007310, 0x02480082, 0x40060205, 0x0000c003,
     } },
-    { { /* 695 */
+    { { /* 696 */
     0x0c020000, 0x02200008, 0x40009000, 0xd161b800,
     0x32744621, 0x3b8af800, 0x8b00050f, 0x2280bbd0,
     } },
-    { { /* 696 */
+    { { /* 697 */
     0x07690600, 0x00438040, 0x50005420, 0x250c41d0,
     0x83108410, 0x02281101, 0x00304008, 0x020040a1,
     } },
-    { { /* 697 */
+    { { /* 698 */
     0x20000040, 0xabe31500, 0xaa443180, 0xc624c2c6,
     0x8004ac13, 0x03d1b000, 0x4285611e, 0x1d9ff303,
     } },
-    { { /* 698 */
+    { { /* 699 */
     0x78e8440a, 0xc3925e26, 0x00852000, 0x4000b001,
     0x88424a90, 0x0c8dca04, 0x4203a705, 0x000422a1,
     } },
-    { { /* 699 */
+    { { /* 700 */
     0x0c018668, 0x10795564, 0xdea00002, 0x40c12000,
     0x5001488b, 0x04000380, 0x50040000, 0x80d0c05d,
     } },
-    { { /* 700 */
+    { { /* 701 */
     0x970aa010, 0x4dafbb20, 0x1e10d921, 0x83140460,
     0xa6d68848, 0x733fd83b, 0x497427bc, 0x92130ddc,
     } },
-    { { /* 701 */
+    { { /* 702 */
     0x8ba1142b, 0xd1392e75, 0x50503009, 0x69008808,
     0x024a49d4, 0x80164010, 0x89d7e564, 0x5316c020,
     } },
-    { { /* 702 */
+    { { /* 703 */
     0x86002b92, 0x15e0a345, 0x0c03008b, 0xe200196e,
     0x80067031, 0xa82916a5, 0x18802000, 0xe1487aac,
     } },
-    { { /* 703 */
+    { { /* 704 */
     0xb5d63207, 0x5f9132e8, 0x20e550a1, 0x10807c00,
     0x9d8a7280, 0x421f00aa, 0x02310e22, 0x04941100,
     } },
-    { { /* 704 */
+    { { /* 705 */
     0x40080022, 0x5c100010, 0xfcc80343, 0x0580a1a5,
     0x04008433, 0x6e080080, 0x81262a4b, 0x2901aad8,
     } },
-    { { /* 705 */
+    { { /* 706 */
     0x4490684d, 0xba880009, 0x00820040, 0x87d10000,
     0xb1e6215b, 0x80083161, 0xc2400800, 0xa600a069,
     } },
-    { { /* 706 */
+    { { /* 707 */
     0x4a328d58, 0x550a5d71, 0x2d579aa0, 0x4aa64005,
     0x30b12021, 0x01123fc6, 0x260a10c2, 0x50824462,
     } },
-    { { /* 707 */
+    { { /* 708 */
     0x80409880, 0x810004c0, 0x00002003, 0x38180000,
     0xf1a60200, 0x720e4434, 0x92e035a2, 0x09008101,
     } },
-    { { /* 708 */
+    { { /* 709 */
     0x00000400, 0x00008885, 0x00000000, 0x00804000,
     0x00000000, 0x00004040, 0x00000000, 0x00000000,
     } },
-    { { /* 709 */
+    { { /* 710 */
     0x00000000, 0x08000000, 0x00000082, 0x00000000,
     0x88000004, 0xe7efbfff, 0xffbfffff, 0xfdffefef,
     } },
-    { { /* 710 */
+    { { /* 711 */
     0xbffefbff, 0x057fffff, 0x85b30034, 0x42164706,
     0xe4105402, 0xb3058092, 0x81305422, 0x180b4263,
     } },
-    { { /* 711 */
+    { { /* 712 */
     0x13f5387b, 0xa9ea07e5, 0x05143c4c, 0x80020600,
     0xbd481ad9, 0xf496ee37, 0x7ec0705f, 0x355fbfb2,
     } },
-    { { /* 712 */
+    { { /* 713 */
     0x455fe644, 0x41469000, 0x063b1d40, 0xfe1362a1,
     0x39028505, 0x0c080548, 0x0000144f, 0x58183488,
     } },
-    { { /* 713 */
+    { { /* 714 */
     0xd8153077, 0x4bfbbd0e, 0x85008a90, 0xe61dc100,
     0xb386ed14, 0x639bff72, 0xd9befd92, 0x0a92887b,
     } },
-    { { /* 714 */
+    { { /* 715 */
     0x1cb2d3fe, 0x177ab980, 0xdc1782c9, 0x3980fffb,
     0x590c4260, 0x37df0f01, 0xb15094a3, 0x23070623,
     } },
-    { { /* 715 */
+    { { /* 716 */
     0x3102f85a, 0x310201f0, 0x1e820040, 0x056a3a0a,
     0x12805b84, 0xa7148002, 0xa04b2612, 0x90011069,
     } },
-    { { /* 716 */
+    { { /* 717 */
     0x848a1000, 0x3f801802, 0x42400708, 0x4e140110,
     0x180080b0, 0x0281c510, 0x10298202, 0x88000210,
     } },
-    { { /* 717 */
+    { { /* 718 */
     0x00420020, 0x11000280, 0x4413e000, 0xfe025804,
     0x30283c07, 0x04739798, 0xcb13ced1, 0x431f6210,
     } },
-    { { /* 718 */
+    { { /* 719 */
     0x55ac278d, 0xc892422e, 0x02885380, 0x78514039,
     0x8088292c, 0x2428b900, 0x080e0c41, 0x42004421,
     } },
-    { { /* 719 */
+    { { /* 720 */
     0x08680408, 0x12040006, 0x02903031, 0xe0855b3e,
     0x10442936, 0x10822814, 0x83344266, 0x531b013c,
     } },
-    { { /* 720 */
+    { { /* 721 */
     0x0e0d0404, 0x00510c22, 0xc0000012, 0x88000040,
     0x0000004a, 0x00000000, 0x5447dff6, 0x00088868,
     } },
-    { { /* 721 */
+    { { /* 722 */
     0x00000081, 0x40000000, 0x00000100, 0x02000000,
     0x00080600, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 722 */
+    { { /* 723 */
     0x00000080, 0x00000040, 0x00000000, 0x00001040,
     0x00000000, 0xf7fdefff, 0xfffeff7f, 0xfffffbff,
     } },
-    { { /* 723 */
+    { { /* 724 */
     0xbffffdff, 0x00ffffff, 0x042012c2, 0x07080c06,
     0x01101624, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 724 */
+    { { /* 725 */
     0xe0000000, 0xfffffffe, 0x7f79ffff, 0x00f928df,
     0x80120c32, 0xd53a0008, 0xecc2d858, 0x2fa89d18,
     } },
-    { { /* 725 */
+    { { /* 726 */
     0xe0109620, 0x2622d60c, 0x02060f97, 0x9055b240,
     0x501180a2, 0x04049800, 0x00004000, 0x00000000,
     } },
-    { { /* 726 */
+    { { /* 727 */
     0x00000000, 0x00000000, 0x00000000, 0xfffffbc0,
     0xdffbeffe, 0x62430b08, 0xfb3b41b6, 0x23896f74,
     } },
-    { { /* 727 */
+    { { /* 728 */
     0xecd7ae7f, 0x5960e047, 0x098fa096, 0xa030612c,
     0x2aaa090d, 0x4f7bd44e, 0x388bc4b2, 0x6110a9c6,
     } },
-    { { /* 728 */
+    { { /* 729 */
     0x42000014, 0x0202800c, 0x6485fe48, 0xe3f7d63e,
     0x0c073aa0, 0x0430e40c, 0x1002f680, 0x00000000,
     } },
-    { { /* 729 */
+    { { /* 730 */
     0x00000000, 0x00000000, 0x00000000, 0x00100000,
     0x00004000, 0x00004000, 0x00000100, 0x00000000,
     } },
-    { { /* 730 */
+    { { /* 731 */
     0x00000000, 0x40000000, 0x00000000, 0x00000400,
     0x00008000, 0x00000000, 0x00400400, 0x00000000,
     } },
-    { { /* 731 */
+    { { /* 732 */
     0x00000000, 0x40000000, 0x00000000, 0x00000800,
     0xfebdffe0, 0xffffffff, 0xfbe77f7f, 0xf7ffffbf,
     } },
-    { { /* 732 */
+    { { /* 733 */
     0xefffffff, 0xdff7ff7e, 0xfbdff6f7, 0x804fbffe,
     0x00000000, 0x00000000, 0x00000000, 0x7fffef00,
     } },
-    { { /* 733 */
+    { { /* 734 */
     0xb6f7ff7f, 0xb87e4406, 0x88313bf5, 0x00f41796,
     0x1391a960, 0x72490080, 0x0024f2f3, 0x42c88701,
     } },
-    { { /* 734 */
+    { { /* 735 */
     0x5048e3d3, 0x43052400, 0x4a4c0000, 0x10580227,
     0x01162820, 0x0014a809, 0x00000000, 0x00683ec0,
     } },
-    { { /* 735 */
+    { { /* 736 */
     0x00000000, 0x00000000, 0x00000000, 0xffe00000,
     0xfddbb7ff, 0x000000f7, 0xc72e4000, 0x00000180,
     } },
-    { { /* 736 */
+    { { /* 737 */
     0x00012000, 0x00004000, 0x00300000, 0xb4f7ffa8,
     0x03ffadf3, 0x00000120, 0x00000000, 0x00000000,
     } },
-    { { /* 737 */
+    { { /* 738 */
     0x00000000, 0x00000000, 0x00000000, 0xfffbf000,
     0xfdcf9df7, 0x15c301bf, 0x810a1827, 0x0a00a842,
     } },
-    { { /* 738 */
+    { { /* 739 */
     0x80088108, 0x18048008, 0x0012a3be, 0x00000000,
     0x00000000, 0x00000000, 0x00000000, 0x00000000,
     } },
-    { { /* 739 */
+    { { /* 740 */
     0x00000000, 0x00000000, 0x00000000, 0x90000000,
     0xdc3769e6, 0x3dff6bff, 0xf3f9fcf8, 0x00000004,
     } },
-    { { /* 740 */
+    { { /* 741 */
     0x80000000, 0xe7eebf6f, 0x5da2dffe, 0xc00b3fd8,
     0xa00c0984, 0x69100040, 0xb912e210, 0x5a0086a5,
     } },
-    { { /* 741 */
+    { { /* 742 */
     0x02896800, 0x6a809005, 0x00030010, 0x80000000,
     0x8e001ff9, 0x00000001, 0x00000000, 0x00000000,
     } },
@@ -3712,126 +3717,128 @@
     LEAF(568,436),
     /* sr */
     LEAF(569,437),
-    /* sv */
+    /* suz */
     LEAF(570,438),
-    /* syr */
+    /* sv */
     LEAF(571,439),
+    /* syr */
+    LEAF(572,440),
     /* szl */
-    LEAF(572,440), LEAF(572,441),
+    LEAF(573,441), LEAF(573,442),
     /* ta */
-    LEAF(574,442),
-    /* te */
     LEAF(575,443),
-    /* tg */
+    /* te */
     LEAF(576,444),
-    /* th */
+    /* tg */
     LEAF(577,445),
+    /* th */
+    LEAF(578,446),
     /* tig */
-    LEAF(578,446), LEAF(578, 45),
+    LEAF(579,447), LEAF(579, 45),
     /* tk */
-    LEAF(580,447), LEAF(580,448),
+    LEAF(581,448), LEAF(581,449),
     /* tr */
-    LEAF(582,449), LEAF(582,140),
+    LEAF(583,450), LEAF(583,140),
     /* tt */
-    LEAF(584,450),
+    LEAF(585,451),
     /* ty */
-    LEAF(585,451), LEAF(585,185), LEAF(585,393),
+    LEAF(586,452), LEAF(586,185), LEAF(586,393),
     /* ug */
-    LEAF(588,452),
-    /* uk */
     LEAF(589,453),
+    /* uk */
+    LEAF(590,454),
     /* und_zmth */
-    LEAF(590,454), LEAF(590,455), LEAF(590,456), LEAF(590,457),
-    LEAF(590,458), LEAF(590,459), LEAF(590,460), LEAF(590,461),
-    LEAF(590,462), LEAF(590,463), LEAF(590,464), LEAF(590,465),
+    LEAF(591,455), LEAF(591,456), LEAF(591,457), LEAF(591,458),
+    LEAF(591,459), LEAF(591,460), LEAF(591,461), LEAF(591,462),
+    LEAF(591,463), LEAF(591,464), LEAF(591,465), LEAF(591,466),
     /* und_zsye */
-    LEAF(602,466), LEAF(602,467), LEAF(602,468), LEAF(602,469),
-    LEAF(602,470), LEAF(602,471), LEAF(602,472), LEAF(602,473),
-    LEAF(602,474), LEAF(602,475), LEAF(602,476), LEAF(602,477),
+    LEAF(603,467), LEAF(603,468), LEAF(603,469), LEAF(603,470),
+    LEAF(603,471), LEAF(603,472), LEAF(603,473), LEAF(603,474),
+    LEAF(603,475), LEAF(603,476), LEAF(603,477), LEAF(603,478),
     /* ve */
-    LEAF(614, 26), LEAF(614,478),
+    LEAF(615, 26), LEAF(615,479),
     /* vi */
-    LEAF(616,479), LEAF(616,480), LEAF(616,481), LEAF(616,482),
+    LEAF(617,480), LEAF(617,481), LEAF(617,482), LEAF(617,483),
     /* vo */
-    LEAF(620,483),
+    LEAF(621,484),
     /* vot */
-    LEAF(621,484), LEAF(621,162),
+    LEAF(622,485), LEAF(622,162),
     /* wa */
-    LEAF(623,485),
+    LEAF(624,486),
     /* wen */
-    LEAF(624,188), LEAF(624,486),
+    LEAF(625,188), LEAF(625,487),
     /* wo */
-    LEAF(626,487), LEAF(626,357),
+    LEAF(627,488), LEAF(627,357),
     /* yap */
-    LEAF(628,488),
+    LEAF(629,489),
     /* yo */
-    LEAF(629,489), LEAF(629,490), LEAF(629,491), LEAF(629,492),
+    LEAF(630,490), LEAF(630,491), LEAF(630,492), LEAF(630,493),
     /* yue */
-    LEAF(633,493), LEAF(633,494), LEAF(633,495), LEAF(633,496),
-    LEAF(633,497), LEAF(633,498), LEAF(633,499), LEAF(633,500),
-    LEAF(633,501), LEAF(633,502), LEAF(633,503), LEAF(633,504),
-    LEAF(633,505), LEAF(633,506), LEAF(633,507), LEAF(633,508),
-    LEAF(633,509), LEAF(633,510), LEAF(633,511), LEAF(633,512),
-    LEAF(633,513), LEAF(633,514), LEAF(633,515), LEAF(633,516),
-    LEAF(633,517), LEAF(633,518), LEAF(633,519), LEAF(633,520),
-    LEAF(633,521), LEAF(633,522), LEAF(633,523), LEAF(633,524),
-    LEAF(633,525), LEAF(633,526), LEAF(633,527), LEAF(633,528),
-    LEAF(633,529), LEAF(633,530), LEAF(633,531), LEAF(633,532),
-    LEAF(633,533), LEAF(633,534), LEAF(633,535), LEAF(633,536),
-    LEAF(633,537), LEAF(633,538), LEAF(633,539), LEAF(633,540),
-    LEAF(633,541), LEAF(633,542), LEAF(633,543), LEAF(633,544),
-    LEAF(633,545), LEAF(633,546), LEAF(633,547), LEAF(633,548),
-    LEAF(633,549), LEAF(633,550), LEAF(633,551), LEAF(633,552),
-    LEAF(633,553), LEAF(633,554), LEAF(633,555), LEAF(633,556),
-    LEAF(633,557), LEAF(633,558), LEAF(633,559), LEAF(633,560),
-    LEAF(633,561), LEAF(633,562), LEAF(633,563), LEAF(633,564),
-    LEAF(633,565), LEAF(633,566), LEAF(633,567), LEAF(633,568),
-    LEAF(633,569), LEAF(633,570), LEAF(633,571), LEAF(633,572),
-    LEAF(633,573), LEAF(633,574), LEAF(633,575), LEAF(633,576),
-    LEAF(633,577), LEAF(633,578), LEAF(633,579), LEAF(633,580),
-    LEAF(633,581), LEAF(633,582), LEAF(633,583), LEAF(633,584),
-    LEAF(633,585), LEAF(633,586), LEAF(633,587), LEAF(633,588),
-    LEAF(633,589), LEAF(633,590), LEAF(633,591), LEAF(633,592),
-    LEAF(633,593), LEAF(633,594), LEAF(633,595), LEAF(633,596),
-    LEAF(633,597), LEAF(633,598), LEAF(633,599), LEAF(633,600),
-    LEAF(633,601), LEAF(633,602), LEAF(633,603), LEAF(633,604),
-    LEAF(633,605), LEAF(633,606), LEAF(633,607), LEAF(633,608),
-    LEAF(633,609), LEAF(633,610), LEAF(633,611), LEAF(633,612),
-    LEAF(633,613), LEAF(633,614), LEAF(633,615), LEAF(633,616),
-    LEAF(633,617), LEAF(633,618), LEAF(633,619), LEAF(633,620),
-    LEAF(633,621), LEAF(633,622), LEAF(633,455), LEAF(633,623),
-    LEAF(633,624), LEAF(633,413), LEAF(633,625), LEAF(633,626),
-    LEAF(633,627), LEAF(633,628), LEAF(633,629), LEAF(633,630),
-    LEAF(633,631), LEAF(633,  3), LEAF(633,632), LEAF(633,633),
-    LEAF(633,634), LEAF(633,635), LEAF(633,636), LEAF(633,637),
-    LEAF(633,622), LEAF(633,638), LEAF(633,639), LEAF(633,640),
-    LEAF(633,641), LEAF(633,642), LEAF(633,643), LEAF(633,644),
-    LEAF(633,645), LEAF(633,646), LEAF(633,647), LEAF(633,648),
-    LEAF(633,649), LEAF(633,650), LEAF(633,651), LEAF(633,652),
-    LEAF(633,653), LEAF(633,654), LEAF(633,655), LEAF(633,656),
-    LEAF(633,657), LEAF(633,658), LEAF(633,659),
+    LEAF(634,494), LEAF(634,495), LEAF(634,496), LEAF(634,497),
+    LEAF(634,498), LEAF(634,499), LEAF(634,500), LEAF(634,501),
+    LEAF(634,502), LEAF(634,503), LEAF(634,504), LEAF(634,505),
+    LEAF(634,506), LEAF(634,507), LEAF(634,508), LEAF(634,509),
+    LEAF(634,510), LEAF(634,511), LEAF(634,512), LEAF(634,513),
+    LEAF(634,514), LEAF(634,515), LEAF(634,516), LEAF(634,517),
+    LEAF(634,518), LEAF(634,519), LEAF(634,520), LEAF(634,521),
+    LEAF(634,522), LEAF(634,523), LEAF(634,524), LEAF(634,525),
+    LEAF(634,526), LEAF(634,527), LEAF(634,528), LEAF(634,529),
+    LEAF(634,530), LEAF(634,531), LEAF(634,532), LEAF(634,533),
+    LEAF(634,534), LEAF(634,535), LEAF(634,536), LEAF(634,537),
+    LEAF(634,538), LEAF(634,539), LEAF(634,540), LEAF(634,541),
+    LEAF(634,542), LEAF(634,543), LEAF(634,544), LEAF(634,545),
+    LEAF(634,546), LEAF(634,547), LEAF(634,548), LEAF(634,549),
+    LEAF(634,550), LEAF(634,551), LEAF(634,552), LEAF(634,553),
+    LEAF(634,554), LEAF(634,555), LEAF(634,556), LEAF(634,557),
+    LEAF(634,558), LEAF(634,559), LEAF(634,560), LEAF(634,561),
+    LEAF(634,562), LEAF(634,563), LEAF(634,564), LEAF(634,565),
+    LEAF(634,566), LEAF(634,567), LEAF(634,568), LEAF(634,569),
+    LEAF(634,570), LEAF(634,571), LEAF(634,572), LEAF(634,573),
+    LEAF(634,574), LEAF(634,575), LEAF(634,576), LEAF(634,577),
+    LEAF(634,578), LEAF(634,579), LEAF(634,580), LEAF(634,581),
+    LEAF(634,582), LEAF(634,583), LEAF(634,584), LEAF(634,585),
+    LEAF(634,586), LEAF(634,587), LEAF(634,588), LEAF(634,589),
+    LEAF(634,590), LEAF(634,591), LEAF(634,592), LEAF(634,593),
+    LEAF(634,594), LEAF(634,595), LEAF(634,596), LEAF(634,597),
+    LEAF(634,598), LEAF(634,599), LEAF(634,600), LEAF(634,601),
+    LEAF(634,602), LEAF(634,603), LEAF(634,604), LEAF(634,605),
+    LEAF(634,606), LEAF(634,607), LEAF(634,608), LEAF(634,609),
+    LEAF(634,610), LEAF(634,611), LEAF(634,612), LEAF(634,613),
+    LEAF(634,614), LEAF(634,615), LEAF(634,616), LEAF(634,617),
+    LEAF(634,618), LEAF(634,619), LEAF(634,620), LEAF(634,621),
+    LEAF(634,622), LEAF(634,623), LEAF(634,456), LEAF(634,624),
+    LEAF(634,625), LEAF(634,413), LEAF(634,626), LEAF(634,627),
+    LEAF(634,628), LEAF(634,629), LEAF(634,630), LEAF(634,631),
+    LEAF(634,632), LEAF(634,  3), LEAF(634,633), LEAF(634,634),
+    LEAF(634,635), LEAF(634,636), LEAF(634,637), LEAF(634,638),
+    LEAF(634,623), LEAF(634,639), LEAF(634,640), LEAF(634,641),
+    LEAF(634,642), LEAF(634,643), LEAF(634,644), LEAF(634,645),
+    LEAF(634,646), LEAF(634,647), LEAF(634,648), LEAF(634,649),
+    LEAF(634,650), LEAF(634,651), LEAF(634,652), LEAF(634,653),
+    LEAF(634,654), LEAF(634,655), LEAF(634,656), LEAF(634,657),
+    LEAF(634,658), LEAF(634,659), LEAF(634,660),
     /* zh_cn */
-    LEAF(804,660), LEAF(804,661), LEAF(804,662), LEAF(804,663),
-    LEAF(804,664), LEAF(804,665), LEAF(804,666), LEAF(804,667),
-    LEAF(804,668), LEAF(804,669), LEAF(804,670), LEAF(804,671),
-    LEAF(804,672), LEAF(804,673), LEAF(804,674), LEAF(804,675),
-    LEAF(804,676), LEAF(804,677), LEAF(804,678), LEAF(804,679),
-    LEAF(804,680), LEAF(804,681), LEAF(804,682), LEAF(804,683),
-    LEAF(804,684), LEAF(804,685), LEAF(804,686), LEAF(804,687),
-    LEAF(804,688), LEAF(804,689), LEAF(804,690), LEAF(804,691),
-    LEAF(804,692), LEAF(804,693), LEAF(804,694), LEAF(804,695),
-    LEAF(804,696), LEAF(804,697), LEAF(804,698), LEAF(804,699),
-    LEAF(804,700), LEAF(804,701), LEAF(804,702), LEAF(804,703),
-    LEAF(804,704), LEAF(804,705), LEAF(804,706), LEAF(804,707),
-    LEAF(804,708), LEAF(804,709), LEAF(804,710), LEAF(804,711),
-    LEAF(804,712), LEAF(804,713), LEAF(804,714), LEAF(804,715),
-    LEAF(804,716), LEAF(804,717), LEAF(804,718), LEAF(804,719),
-    LEAF(804,720), LEAF(804,721), LEAF(804,722), LEAF(804,723),
-    LEAF(804,724), LEAF(804,725), LEAF(804,726), LEAF(804,727),
-    LEAF(804,728), LEAF(804,729), LEAF(804,730), LEAF(804,731),
-    LEAF(804,732), LEAF(804,733), LEAF(804,734), LEAF(804,735),
-    LEAF(804,736), LEAF(804,737), LEAF(804,738), LEAF(804,739),
-    LEAF(804,740), LEAF(804,741),
+    LEAF(805,661), LEAF(805,662), LEAF(805,663), LEAF(805,664),
+    LEAF(805,665), LEAF(805,666), LEAF(805,667), LEAF(805,668),
+    LEAF(805,669), LEAF(805,670), LEAF(805,671), LEAF(805,672),
+    LEAF(805,673), LEAF(805,674), LEAF(805,675), LEAF(805,676),
+    LEAF(805,677), LEAF(805,678), LEAF(805,679), LEAF(805,680),
+    LEAF(805,681), LEAF(805,682), LEAF(805,683), LEAF(805,684),
+    LEAF(805,685), LEAF(805,686), LEAF(805,687), LEAF(805,688),
+    LEAF(805,689), LEAF(805,690), LEAF(805,691), LEAF(805,692),
+    LEAF(805,693), LEAF(805,694), LEAF(805,695), LEAF(805,696),
+    LEAF(805,697), LEAF(805,698), LEAF(805,699), LEAF(805,700),
+    LEAF(805,701), LEAF(805,702), LEAF(805,703), LEAF(805,704),
+    LEAF(805,705), LEAF(805,706), LEAF(805,707), LEAF(805,708),
+    LEAF(805,709), LEAF(805,710), LEAF(805,711), LEAF(805,712),
+    LEAF(805,713), LEAF(805,714), LEAF(805,715), LEAF(805,716),
+    LEAF(805,717), LEAF(805,718), LEAF(805,719), LEAF(805,720),
+    LEAF(805,721), LEAF(805,722), LEAF(805,723), LEAF(805,724),
+    LEAF(805,725), LEAF(805,726), LEAF(805,727), LEAF(805,728),
+    LEAF(805,729), LEAF(805,730), LEAF(805,731), LEAF(805,732),
+    LEAF(805,733), LEAF(805,734), LEAF(805,735), LEAF(805,736),
+    LEAF(805,737), LEAF(805,738), LEAF(805,739), LEAF(805,740),
+    LEAF(805,741), LEAF(805,742),
 },
 {
     /* aa */
@@ -4211,6 +4218,8 @@
     0x0000,
     /* sr */
     0x0004,
+    /* suz */
+    0x011b,
     /* sv */
     0x0000,
     /* syr */
@@ -4528,6 +4537,7 @@
     148, /* ss */
     149, /* st */
     234, /* su */
+    281, /* suz */
     150, /* sv */
     151, /* sw */
     152, /* syr */
@@ -4733,46 +4743,46 @@
     224, /* sr */
     225, /* ss */
     226, /* st */
-    228, /* sv */
-    229, /* sw */
-    230, /* syr */
-    232, /* ta */
-    234, /* te */
-    235, /* tg */
-    236, /* th */
-    238, /* ti_er */
-    239, /* ti_et */
-    240, /* tig */
-    241, /* tk */
-    242, /* tl */
-    243, /* tn */
-    244, /* to */
-    246, /* tr */
-    247, /* ts */
-    248, /* tt */
-    249, /* tw */
-    251, /* tyv */
-    252, /* ug */
-    253, /* uk */
-    257, /* ur */
-    258, /* uz */
-    259, /* ve */
-    260, /* vi */
-    261, /* vo */
-    262, /* vot */
-    263, /* wa */
-    266, /* wen */
-    267, /* wo */
-    268, /* xh */
-    269, /* yap */
-    270, /* yi */
-    271, /* yo */
-    275, /* zh_cn */
-    276, /* zh_hk */
-    277, /* zh_mo */
-    278, /* zh_sg */
-    279, /* zh_tw */
-    280, /* zu */
+    229, /* sv */
+    230, /* sw */
+    231, /* syr */
+    233, /* ta */
+    235, /* te */
+    236, /* tg */
+    237, /* th */
+    239, /* ti_er */
+    240, /* ti_et */
+    241, /* tig */
+    242, /* tk */
+    243, /* tl */
+    244, /* tn */
+    245, /* to */
+    247, /* tr */
+    248, /* ts */
+    249, /* tt */
+    250, /* tw */
+    252, /* tyv */
+    253, /* ug */
+    254, /* uk */
+    258, /* ur */
+    259, /* uz */
+    260, /* ve */
+    261, /* vi */
+    262, /* vo */
+    263, /* vot */
+    264, /* wa */
+    267, /* wen */
+    268, /* wo */
+    269, /* xh */
+    270, /* yap */
+    271, /* yi */
+    272, /* yo */
+    276, /* zh_cn */
+    277, /* zh_hk */
+    278, /* zh_mo */
+    279, /* zh_sg */
+    280, /* zh_tw */
+    281, /* zu */
     4, /* ak */
     6, /* an */
     19, /* ber_dz */
@@ -4818,23 +4828,23 @@
     213, /* sid */
     221, /* sn */
     227, /* su */
-    250, /* ty */
-    265, /* wal */
-    274, /* za */
+    251, /* ty */
+    266, /* wal */
+    275, /* za */
     130, /* lah */
     172, /* nqo */
     31, /* brx */
     201, /* sat */
     52, /* doi */
     154, /* mni */
-    255, /* und_zsye */
-    254, /* und_zmth */
+    256, /* und_zsye */
+    255, /* und_zmth */
     7, /* anp */
     23, /* bhb */
     86, /* hif */
     141, /* mag */
     192, /* raj */
-    237, /* the */
+    238, /* the */
     3, /* agr */
     13, /* ayc */
     18, /* bem */
@@ -4855,19 +4865,20 @@
     193, /* rif */
     208, /* sgs */
     210, /* shn */
-    231, /* szl */
-    233, /* tcy */
-    245, /* tpi */
-    256, /* unm */
-    264, /* wae */
-    272, /* yue */
-    273, /* yuw */
+    232, /* szl */
+    234, /* tcy */
+    246, /* tpi */
+    257, /* unm */
+    265, /* wae */
+    273, /* yue */
+    274, /* yuw */
     78, /* got */
     43, /* cop */
+    228, /* suz */
 }
 };
 
-#define NUM_LANG_CHAR_SET	281
+#define NUM_LANG_CHAR_SET	282
 #define NUM_LANG_SET_MAP	9
 
 static const FcChar32 fcLangCountrySets[][NUM_LANG_SET_MAP] = {
@@ -4905,13 +4916,13 @@
     { 182, 189 }, /* p */
     { 190, 191 }, /* q */
     { 192, 198 }, /* r */
-    { 199, 231 }, /* s */
-    { 232, 251 }, /* t */
-    { 252, 258 }, /* u */
-    { 259, 262 }, /* v */
-    { 263, 267 }, /* w */
-    { 268, 268 }, /* x */
-    { 269, 273 }, /* y */
-    { 274, 280 }, /* z */
+    { 199, 232 }, /* s */
+    { 233, 252 }, /* t */
+    { 253, 259 }, /* u */
+    { 260, 263 }, /* v */
+    { 264, 268 }, /* w */
+    { 269, 269 }, /* x */
+    { 270, 274 }, /* y */
+    { 275, 281 }, /* z */
 };
 
diff --git a/third_party/fontconfig/include/fontconfig/fontconfig.h b/third_party/fontconfig/include/fontconfig/fontconfig.h
index 891b6d45..03575894 100644
--- a/third_party/fontconfig/include/fontconfig/fontconfig.h
+++ b/third_party/fontconfig/include/fontconfig/fontconfig.h
@@ -54,8 +54,8 @@
  */
 
 #define FC_MAJOR                2
-#define FC_MINOR                16
-#define FC_REVISION             2
+#define FC_MINOR                17
+#define FC_REVISION             1
 
 #define FC_VERSION              ((FC_MAJOR * 10000) + (FC_MINOR * 100) + (FC_REVISION))
 
diff --git a/third_party/fontconfig/include/meson-config.h b/third_party/fontconfig/include/meson-config.h
index 23e1d8ca..bdf0ab03 100644
--- a/third_party/fontconfig/include/meson-config.h
+++ b/third_party/fontconfig/include/meson-config.h
@@ -148,13 +148,13 @@
 
 #define PACKAGE_NAME "fontconfig"
 
-#define PACKAGE_STRING "fontconfig 2.16.2"
+#define PACKAGE_STRING "fontconfig 2.17.1"
 
 #define PACKAGE_TARNAME "fontconfig"
 
 #define PACKAGE_URL ""
 
-#define PACKAGE_VERSION "2.16.2"
+#define PACKAGE_VERSION "2.17.1"
 
 #define SIZEOF_VOID_P 8
 
diff --git a/third_party/fontconfig/include/src/fcobjshash.h b/third_party/fontconfig/include/src/fcobjshash.h
index c5c8cf6..0e4aae3 100644
--- a/third_party/fontconfig/include/src/fcobjshash.h
+++ b/third_party/fontconfig/include/src/fcobjshash.h
@@ -1,5 +1,5 @@
-/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: /usr/bin/gperf --pic -m 100 --output-file src/fcobjshash.h src/fcobjshash.gperf  */
+/* ANSI-C code produced by gperf version 3.2.1 */
+/* Command-line: gperf --pic -m 100 --output-file src/fcobjshash.h src/fcobjshash.gperf  */
 /* Computed positions: -k'3,5' */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@@ -84,6 +84,11 @@
     {
       default:
         hval += asso_values[(unsigned char)str[4]];
+#if (defined __cplusplus && (__cplusplus >= 201703L || (__cplusplus >= 201103L && defined __clang__ && __clang_major__ + (__clang_minor__ >= 9) > 3))) || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 202000L && ((defined __GNUC__ && __GNUC__ >= 10) || (defined __clang__ && __clang_major__ >= 9)))
+      [[fallthrough]];
+#elif (defined __GNUC__ && __GNUC__ >= 7) || (defined __clang__ && __clang_major__ >= 10)
+      __attribute__ ((__fallthrough__));
+#endif
       /*FALLTHROUGH*/
       case 4:
       case 3:
@@ -222,6 +227,10 @@
       MAX_HASH_VALUE = 62
     };
 
+#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
   static const struct FcObjectTypeInfo wordlist[] =
     {
       {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
@@ -337,6 +346,9 @@
 #line 72 "src/fcobjshash.gperf"
       {(int)(size_t)&((struct FcObjectTypeNamePool_t *)0)->FcObjectTypeNamePool_str62,FC_FONT_WRAPPER_OBJECT}
     };
+#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 6) > 4) || (defined __clang__ && __clang_major__ >= 3)
+#pragma GCC diagnostic pop
+#endif
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
     {
@@ -354,5 +366,5 @@
             }
         }
     }
-  return 0;
+  return (struct FcObjectTypeInfo *) 0;
 }
diff --git a/third_party/fontconfig/src b/third_party/fontconfig/src
index c527fe1..8f169b6 160000
--- a/third_party/fontconfig/src
+++ b/third_party/fontconfig/src
@@ -1 +1 @@
-Subproject commit c527fe1452d469e5fa1a211180dd40bcdb79fb2a
+Subproject commit 8f169b6a9c6be7e8f1fa3480d93b33befa6bee3f
diff --git a/third_party/googletest/src b/third_party/googletest/src
index 7e17b15..32f9f4c 160000
--- a/third_party/googletest/src
+++ b/third_party/googletest/src
@@ -1 +1 @@
-Subproject commit 7e17b15f1547bb8dd9c2fed91043b7af3437387f
+Subproject commit 32f9f4c82afa4249af66b55278df15c16b3031ea
diff --git a/third_party/grpc-java/BUILD.gn b/third_party/grpc-java/BUILD.gn
index 7dfc645..7190454 100644
--- a/third_party/grpc-java/BUILD.gn
+++ b/third_party/grpc-java/BUILD.gn
@@ -31,5 +31,9 @@
       "//third_party/protobuf:protobuf_config",
       ":grpc_java_plugin_internal_config",
     ]
+
+    # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+    # enable the diagnostic by removing this line.
+    configs += [ "//build/config/compiler:no_exit_time_destructors" ]
   }
 }
diff --git a/third_party/ijar/BUILD.gn b/third_party/ijar/BUILD.gn
index 3459415..aae76525 100644
--- a/third_party/ijar/BUILD.gn
+++ b/third_party/ijar/BUILD.gn
@@ -38,5 +38,9 @@
       configs -= [ "//build/config:debug" ]
       configs += [ "//build/config:release" ]
     }
+
+    # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+    # enable the diagnostic by removing this line.
+    configs += [ "//build/config/compiler:no_exit_time_destructors" ]
   }
 }
diff --git a/third_party/jetstream/main b/third_party/jetstream/main
index 8c28a5f..df197ef 160000
--- a/third_party/jetstream/main
+++ b/third_party/jetstream/main
@@ -1 +1 @@
-Subproject commit 8c28a5fbd8971332b0ffd312a0352bed5c21353e
+Subproject commit df197ef3b188771bcfb28b7b32565b281d337950
diff --git a/third_party/jni_zero/BUILD.gn b/third_party/jni_zero/BUILD.gn
index 31a6f3d6..7056bdd 100644
--- a/third_party/jni_zero/BUILD.gn
+++ b/third_party/jni_zero/BUILD.gn
@@ -60,6 +60,10 @@
   ]
   configs += [ ":jni_include_dir" ]
 
+  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
+  # enable the diagnostic by removing this line.
+  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
+
   defines = []
   if (enable_jni_multiplexing) {
     defines += [ "JNI_ZERO_MULTIPLEXING_ENABLED" ]
diff --git a/third_party/jni_zero/codegen/called_by_native_header.py b/third_party/jni_zero/codegen/called_by_native_header.py
index d0a2bccf..037d3ae 100644
--- a/third_party/jni_zero/codegen/called_by_native_header.py
+++ b/third_party/jni_zero/codegen/called_by_native_header.py
@@ -139,5 +139,5 @@
         sb(f'{jobject_type} _ret2 = static_cast<{jobject_type}>(_ret);\n')
 
       with sb.statement():
-        sb(f'return jni_zero::ScopedJavaLocalRef<{jobject_type}>(env, '
+        sb(f'return jni_zero::ScopedJavaLocalRef<{jobject_type}>::Adopt(env, '
            f'{return_rvalue})')
diff --git a/third_party/jni_zero/codegen/convert_type.py b/third_party/jni_zero/codegen/convert_type.py
index 68a8ec4..fba3ac9 100644
--- a/third_party/jni_zero/codegen/convert_type.py
+++ b/third_party/jni_zero/codegen/convert_type.py
@@ -93,7 +93,7 @@
     jtype = 'jobject'
 
   if release_ref:
-    rvalue = f'jni_zero::ScopedJavaLocalRef<{jtype}>(env, {rvalue})'
+    rvalue = f'jni_zero::ScopedJavaLocalRef<{jtype}>::Adopt(env, {rvalue})'
   else:
     rvalue = f'jni_zero::JavaRef<{jtype}>::CreateLeaky(env, {rvalue})'
 
diff --git a/third_party/jni_zero/default_conversions.cc b/third_party/jni_zero/default_conversions.cc
index bf316fd..de2f1b77 100644
--- a/third_party/jni_zero/default_conversions.cc
+++ b/third_party/jni_zero/default_conversions.cc
@@ -31,7 +31,7 @@
     CheckException(env);                                                  \
     env->Set##J##ArrayRegion(arr, 0, array_jsize,                         \
                              reinterpret_cast<const JTYPE*>(vec.data())); \
-    return ScopedJavaLocalRef<jarray>(env, arr);                          \
+    return ScopedJavaLocalRef<jarray>::Adopt(env, arr);                   \
   }
 
 PRIMITIVE_ARRAY_CONVERSIONS(int64_t, jlong, Long)
@@ -77,7 +77,7 @@
   jbooleanArray j_array = env->NewBooleanArray(array_jsize);
   CheckException(env);
   env->SetBooleanArrayRegion(j_array, 0, array_jsize, arr.get());
-  return ScopedJavaLocalRef<jarray>(env, j_array);
+  return ScopedJavaLocalRef<jarray>::Adopt(env, j_array);
 }
 }  // namespace jni_zero
 #endif  // JNI_ZERO_ENABLE_TYPE_CONVERSIONS
diff --git a/third_party/jni_zero/default_conversions.h b/third_party/jni_zero/default_conversions.h
index 68ebaec..8b21a08 100644
--- a/third_party/jni_zero/default_conversions.h
+++ b/third_party/jni_zero/default_conversions.h
@@ -63,9 +63,9 @@
     // Do not call FromJni for jobject->jobject.
     if constexpr (std::is_base_of_v<JavaRef<jobject>, ElementType>) {
       if constexpr (has_push_back) {
-        ret.emplace_back(env, j_element);
+        ret.push_back(ElementType::Adopt(env, j_element));
       } else if constexpr (has_insert) {
-        ret.emplace(env, j_element);
+        ret.insert(ElementType::Adopt(env, j_element));
       }
     } else {
       auto element = ScopedJavaLocalRef<jobject>::Adopt(env, j_element);
@@ -100,7 +100,7 @@
     }
     ++i;
   }
-  return ScopedJavaLocalRef<jobjectArray>(env, j_array);
+  return ScopedJavaLocalRef<jobjectArray>::Adopt(env, j_array);
 }
 
 #define DECLARE_PRIMITIVE_ARRAY_CONVERSIONS(T)                                 \
diff --git a/third_party/jni_zero/java_refs.cc b/third_party/jni_zero/java_refs.cc
index 9e288ccd..25e0144 100644
--- a/third_party/jni_zero/java_refs.cc
+++ b/third_party/jni_zero/java_refs.cc
@@ -103,7 +103,7 @@
 
 ScopedJavaLocalRef<jobject> ScopedJavaGlobalWeakRef::get(JNIEnv* env) const {
   jobject real = obj_ ? real = env->NewLocalRef(obj_) : nullptr;
-  return ScopedJavaLocalRef<jobject>(env, real);
+  return ScopedJavaLocalRef<jobject>::Adopt(env, real);
 }
 
 void ScopedJavaGlobalWeakRef::Assign(const ScopedJavaGlobalWeakRef& other) {
diff --git a/third_party/jni_zero/java_refs.h b/third_party/jni_zero/java_refs.h
index 4e8727a0..1db45c8 100644
--- a/third_party/jni_zero/java_refs.h
+++ b/third_party/jni_zero/java_refs.h
@@ -131,7 +131,7 @@
 };
 
 // Forward declare the object array reader for the convenience function.
-template <typename T>
+template <typename T = jobject>
 class JavaObjectArrayReader;
 
 // Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
diff --git a/third_party/jni_zero/jni_zero.cc b/third_party/jni_zero/jni_zero.cc
index 5eda1d747..4c689c3 100644
--- a/third_party/jni_zero/jni_zero.cc
+++ b/third_party/jni_zero/jni_zero.cc
@@ -134,7 +134,7 @@
   g_object_class = GetSystemClassGlobalRef(env, "java/lang/Object");
   g_string_class = GetSystemClassGlobalRef(env, "java/lang/String");
   g_empty_string.Reset(
-      env, ScopedJavaLocalRef<jstring>(env, env->NewString(nullptr, 0)));
+      env, ScopedJavaLocalRef<jstring>::Adopt(env, env->NewString(nullptr, 0)));
 #if defined(JNI_ZERO_MULTIPLEXING_ENABLED)
   Java_JniInit_crashIfMultiplexingMisaligned(env, kJniZeroHashWhole,
                                              kJniZeroHashPriority);
@@ -144,10 +144,10 @@
 #endif
   ScopedJavaLocalRef<jobjectArray> globals = Java_JniInit_init(env);
   g_empty_list.Reset(env,
-                     ScopedJavaLocalRef<jobject>(
+                     ScopedJavaLocalRef<jobject>::Adopt(
                          env, env->GetObjectArrayElement(globals.obj(), 0)));
   g_empty_map.Reset(env,
-                    ScopedJavaLocalRef<jobject>(
+                    ScopedJavaLocalRef<jobject>::Adopt(
                         env, env->GetObjectArrayElement(globals.obj(), 1)));
 }
 
@@ -199,12 +199,13 @@
 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env,
                                     const char* class_name,
                                     const char* split_name) {
-  return ScopedJavaLocalRef<jclass>(
+  return ScopedJavaLocalRef<jclass>::Adopt(
       env, GetClassInternal(env, class_name, split_name));
 }
 
 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
-  return ScopedJavaLocalRef<jclass>(env, GetClassInternal(env, class_name, ""));
+  return ScopedJavaLocalRef<jclass>::Adopt(
+      env, GetClassInternal(env, class_name, ""));
 }
 
 template <MethodID::Type type>
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 66db47d..43e8a29 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
@@ -383,7 +383,7 @@
       "(II)V",
       &cached_method_id);
   auto _ret = env->NewObject(clazz, call_context.method_id(), as_jint(foo), as_jint(bar));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_addStructA(
@@ -401,7 +401,7 @@
       "(Lorg/jni_zero/SampleForTests$InnerStructA;)Lorg/jni_zero/SampleForTests$InnerStructA;",
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), a.obj());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jclass> Java_SampleForTests_getClass(
@@ -420,7 +420,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), arg0.obj());
   jclass _ret2 = static_cast<jclass>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jclass>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jclass>::Adopt(env, _ret2);
 }
 
 static std::string Java_SampleForTests_getFirstString(
@@ -448,7 +448,9 @@
       call_context.method_id(),
       converted_array.obj(),
       converted_finalArg.obj());
-  return jni_zero::FromJniType<std::string>(env, jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+  return jni_zero::FromJniType<std::string>(
+      env,
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(JNIEnv* env) {
@@ -463,7 +465,7 @@
       "()Lorg/jni_zero/SampleForTests$InnerEnum;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(
@@ -480,7 +482,7 @@
       "(I)Lorg/jni_zero/SampleForTests$InnerEnum;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), as_jint(a));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerInterface(JNIEnv* env) {
@@ -495,7 +497,7 @@
       "()Lorg/jni_zero/SampleForTests$InnerInterface;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jthrowable> Java_SampleForTests_getThrowable(
@@ -514,7 +516,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), arg0.obj());
   jthrowable _ret2 = static_cast<jthrowable>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jthrowable>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jthrowable>::Adopt(env, _ret2);
 }
 
 static void Java_SampleForTests_iterateAndDoSomething(
@@ -585,7 +587,7 @@
       converted_bat);
   return jni_zero::FromJniArray<std::vector<int32_t>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jintArray>(env, static_cast<jintArray>(_ret)));
+      jni_zero::ScopedJavaLocalRef<jintArray>::Adopt(env, static_cast<jintArray>(_ret)));
 }
 
 static std::vector<jni_zero::ScopedJavaLocalRef<jobject>> Java_SampleForTests_listTest1(
@@ -605,7 +607,7 @@
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), converted_items.obj());
   return jni_zero::FromJniCollection<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static std::map<std::string, std::string> Java_SampleForTests_mapTest1(
@@ -625,7 +627,7 @@
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), converted_arg0.obj());
   return jni_zero::FromJniType<std::map<std::string, std::string>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static void Java_SampleForTests_methodThatThrowsException(
@@ -733,7 +735,7 @@
       converted_d.obj());
   return jni_zero::FromJniArray<std::vector<bool>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jbooleanArray>(env, static_cast<jbooleanArray>(_ret)));
+      jni_zero::ScopedJavaLocalRef<jbooleanArray>::Adopt(env, static_cast<jbooleanArray>(_ret)));
 }
 
 static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
@@ -767,7 +769,7 @@
       "(JILjava/lang/String;)Lorg/jni_zero/SampleForTests$InnerStructA;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), l, as_jint(i), s.obj());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jlong Java_InnerStructB_getKey(JNIEnv* env, const jni_zero::JavaRef<jobject>& obj) {
@@ -800,7 +802,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id());
   jstring _ret2 = static_cast<jstring>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jstring>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jstring>::Adopt(env, _ret2);
 }
 
 
diff --git a/third_party/jni_zero/test/golden/testBirectionalNonProxy-SampleBidirectionalNonProxy_jni.h.golden b/third_party/jni_zero/test/golden/testBirectionalNonProxy-SampleBidirectionalNonProxy_jni.h.golden
index d3c5a11..5c7501d 100644
--- a/third_party/jni_zero/test/golden/testBirectionalNonProxy-SampleBidirectionalNonProxy_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testBirectionalNonProxy-SampleBidirectionalNonProxy_jni.h.golden
@@ -187,7 +187,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), as_jint(iParam));
   jstring _ret2 = static_cast<jstring>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jstring>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jstring>::Adopt(env, _ret2);
 }
 
 static jni_zero::ScopedJavaLocalRef<jstring> Java_SampleBidirectionalNonProxy_testStaticMethodWithNoParam(
@@ -204,7 +204,7 @@
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
   jstring _ret2 = static_cast<jstring>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jstring>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jstring>::Adopt(env, _ret2);
 }
 
 static jint Java_SampleBidirectionalNonProxy_testStaticMethodWithParam(
diff --git a/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden b/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden
index 466112ad..063b796 100644
--- a/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden
+++ b/third_party/jni_zero/test/golden/testFromClassFile-JavapClass_jni.h.golden
@@ -49,7 +49,7 @@
       "()V",
       &cached_method_id);
   auto _ret = env->NewObject(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 [[maybe_unused]] static jni_zero::ScopedJavaLocalRef<jobject> Java_JavapClass_Constructor__boolean(
@@ -66,7 +66,7 @@
       "(Z)V",
       &cached_method_id);
   auto _ret = env->NewObject(clazz, call_context.method_id(), p0);
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 [[maybe_unused]] static jni_zero::ScopedJavaLocalRef<jobject> Java_JavapClass_Constructor__int(
@@ -83,7 +83,7 @@
       "(I)V",
       &cached_method_id);
   auto _ret = env->NewObject(clazz, call_context.method_id(), as_jint(p0));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 [[maybe_unused]] static jint Java_JavapClass_intMethod(
@@ -167,7 +167,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), p0.obj(), p1.obj());
   jclass _ret2 = static_cast<jclass>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jclass>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jclass>::Adopt(env, _ret2);
 }
 
 [[maybe_unused]] static jint Java_JavapClass_staticIntMethod(
@@ -203,7 +203,7 @@
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), p0.obj());
   jobjectArray _ret2 = static_cast<jobjectArray>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jobjectArray>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jobjectArray>::Adopt(env, _ret2);
 }
 
 
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 ba306d2..9cf0396 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
@@ -383,7 +383,7 @@
       "(II)V",
       &cached_method_id);
   auto _ret = env->NewObject(clazz, call_context.method_id(), as_jint(foo), as_jint(bar));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_addStructA(
@@ -401,7 +401,7 @@
       "(Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerStructA;)Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerStructA;",
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), a.obj());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jclass> Java_SampleForTests_getClass(
@@ -420,7 +420,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), arg0.obj());
   jclass _ret2 = static_cast<jclass>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jclass>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jclass>::Adopt(env, _ret2);
 }
 
 static std::string Java_SampleForTests_getFirstString(
@@ -448,7 +448,9 @@
       call_context.method_id(),
       converted_array.obj(),
       converted_finalArg.obj());
-  return jni_zero::FromJniType<std::string>(env, jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+  return jni_zero::FromJniType<std::string>(
+      env,
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(JNIEnv* env) {
@@ -463,7 +465,7 @@
       "()Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerEnum;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(
@@ -480,7 +482,7 @@
       "(I)Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerEnum;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), as_jint(a));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerInterface(JNIEnv* env) {
@@ -495,7 +497,7 @@
       "()Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerInterface;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jthrowable> Java_SampleForTests_getThrowable(
@@ -514,7 +516,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), arg0.obj());
   jthrowable _ret2 = static_cast<jthrowable>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jthrowable>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jthrowable>::Adopt(env, _ret2);
 }
 
 static void Java_SampleForTests_iterateAndDoSomething(
@@ -585,7 +587,7 @@
       converted_bat);
   return jni_zero::FromJniArray<std::vector<int32_t>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jintArray>(env, static_cast<jintArray>(_ret)));
+      jni_zero::ScopedJavaLocalRef<jintArray>::Adopt(env, static_cast<jintArray>(_ret)));
 }
 
 static std::vector<jni_zero::ScopedJavaLocalRef<jobject>> Java_SampleForTests_listTest1(
@@ -605,7 +607,7 @@
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), converted_items.obj());
   return jni_zero::FromJniCollection<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static std::map<std::string, std::string> Java_SampleForTests_mapTest1(
@@ -625,7 +627,7 @@
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), converted_arg0.obj());
   return jni_zero::FromJniType<std::map<std::string, std::string>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static void Java_SampleForTests_methodThatThrowsException(
@@ -733,7 +735,7 @@
       converted_d.obj());
   return jni_zero::FromJniArray<std::vector<bool>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jbooleanArray>(env, static_cast<jbooleanArray>(_ret)));
+      jni_zero::ScopedJavaLocalRef<jbooleanArray>::Adopt(env, static_cast<jbooleanArray>(_ret)));
 }
 
 static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
@@ -767,7 +769,7 @@
       "(JILjava/lang/String;)Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerStructA;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), l, as_jint(i), s.obj());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jlong Java_InnerStructB_getKey(JNIEnv* env, const jni_zero::JavaRef<jobject>& obj) {
@@ -800,7 +802,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id());
   jstring _ret2 = static_cast<jstring>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jstring>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jstring>::Adopt(env, _ret2);
 }
 
 
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 ba306d2..9cf0396 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
@@ -383,7 +383,7 @@
       "(II)V",
       &cached_method_id);
   auto _ret = env->NewObject(clazz, call_context.method_id(), as_jint(foo), as_jint(bar));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_addStructA(
@@ -401,7 +401,7 @@
       "(Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerStructA;)Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerStructA;",
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), a.obj());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jclass> Java_SampleForTests_getClass(
@@ -420,7 +420,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), arg0.obj());
   jclass _ret2 = static_cast<jclass>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jclass>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jclass>::Adopt(env, _ret2);
 }
 
 static std::string Java_SampleForTests_getFirstString(
@@ -448,7 +448,9 @@
       call_context.method_id(),
       converted_array.obj(),
       converted_finalArg.obj());
-  return jni_zero::FromJniType<std::string>(env, jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+  return jni_zero::FromJniType<std::string>(
+      env,
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(JNIEnv* env) {
@@ -463,7 +465,7 @@
       "()Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerEnum;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(
@@ -480,7 +482,7 @@
       "(I)Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerEnum;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), as_jint(a));
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerInterface(JNIEnv* env) {
@@ -495,7 +497,7 @@
       "()Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerInterface;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jni_zero::ScopedJavaLocalRef<jthrowable> Java_SampleForTests_getThrowable(
@@ -514,7 +516,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id(), arg0.obj());
   jthrowable _ret2 = static_cast<jthrowable>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jthrowable>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jthrowable>::Adopt(env, _ret2);
 }
 
 static void Java_SampleForTests_iterateAndDoSomething(
@@ -585,7 +587,7 @@
       converted_bat);
   return jni_zero::FromJniArray<std::vector<int32_t>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jintArray>(env, static_cast<jintArray>(_ret)));
+      jni_zero::ScopedJavaLocalRef<jintArray>::Adopt(env, static_cast<jintArray>(_ret)));
 }
 
 static std::vector<jni_zero::ScopedJavaLocalRef<jobject>> Java_SampleForTests_listTest1(
@@ -605,7 +607,7 @@
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), converted_items.obj());
   return jni_zero::FromJniCollection<std::vector<jni_zero::ScopedJavaLocalRef<jobject>>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static std::map<std::string, std::string> Java_SampleForTests_mapTest1(
@@ -625,7 +627,7 @@
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), converted_arg0.obj());
   return jni_zero::FromJniType<std::map<std::string, std::string>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jobject>(env, _ret));
+      jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret));
 }
 
 static void Java_SampleForTests_methodThatThrowsException(
@@ -733,7 +735,7 @@
       converted_d.obj());
   return jni_zero::FromJniArray<std::vector<bool>>(
       env,
-      jni_zero::ScopedJavaLocalRef<jbooleanArray>(env, static_cast<jbooleanArray>(_ret)));
+      jni_zero::ScopedJavaLocalRef<jbooleanArray>::Adopt(env, static_cast<jbooleanArray>(_ret)));
 }
 
 static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
@@ -767,7 +769,7 @@
       "(JILjava/lang/String;)Lthis/is/a/package/prefix/org/jni_zero/SampleForTests$InnerStructA;",
       &cached_method_id);
   auto _ret = env->CallStaticObjectMethod(clazz, call_context.method_id(), l, as_jint(i), s.obj());
-  return jni_zero::ScopedJavaLocalRef<jobject>(env, _ret);
+  return jni_zero::ScopedJavaLocalRef<jobject>::Adopt(env, _ret);
 }
 
 static jlong Java_InnerStructB_getKey(JNIEnv* env, const jni_zero::JavaRef<jobject>& obj) {
@@ -800,7 +802,7 @@
       &cached_method_id);
   auto _ret = env->CallObjectMethod(obj.obj(), call_context.method_id());
   jstring _ret2 = static_cast<jstring>(_ret);
-  return jni_zero::ScopedJavaLocalRef<jstring>(env, _ret2);
+  return jni_zero::ScopedJavaLocalRef<jstring>::Adopt(env, _ret2);
 }
 
 
diff --git a/third_party/lens_server_proto/README.chromium b/third_party/lens_server_proto/README.chromium
index 7918dc2..75596dcc 100644
--- a/third_party/lens_server_proto/README.chromium
+++ b/third_party/lens_server_proto/README.chromium
@@ -1,7 +1,7 @@
 Name: Lens Protos
 Short Name: lens_overlay_proto
 URL: This is the canonical public repository
-Version: 785470124
+Version: 785470200
 Date: 2025-07-21
 License: BSD-3-Clause
 License File: LICENSE
@@ -20,4 +20,4 @@
 
 
 Local Modifications:
-Unchanged from the output of the export script.
+Comment for time_usec in request_id needs update on server copy.
diff --git a/third_party/lens_server_proto/lens_overlay_request_id.proto b/third_party/lens_server_proto/lens_overlay_request_id.proto
index 21408eb0e..734003af 100644
--- a/third_party/lens_server_proto/lens_overlay_request_id.proto
+++ b/third_party/lens_server_proto/lens_overlay_request_id.proto
@@ -11,7 +11,7 @@
 import "lens_overlay_routing_info.proto";
 
 // Request Id definition to support request sequencing and state lookup.
-// Next Id: 10
+// Next Id: 11
 message LensOverlayRequestId {
   // A unique identifier for a sequence of related Lens requests.
   uint64 uuid = 1;
@@ -41,4 +41,13 @@
 
   // The Epoch Micro Wall time when the request id is built.
   uint64 time_usec = 7;
+
+  enum MediaType {
+    MEDIA_TYPE_DEFAULT_IMAGE = 0;
+    MEDIA_TYPE_PDF = 1;
+    MEDIA_TYPE_WEBPAGE = 2;
+  }
+
+  // The type of media this object represents.
+  MediaType media_type = 10;
 }
diff --git a/third_party/libFuzzer/BUILD.gn b/third_party/libFuzzer/BUILD.gn
index c54e68ed..6f60963c 100644
--- a/third_party/libFuzzer/BUILD.gn
+++ b/third_party/libFuzzer/BUILD.gn
@@ -51,7 +51,10 @@
 
   configs -= fuzzing_engine_remove_configs
   configs += fuzzing_engine_add_configs
-  configs += [ ":warnings" ]
+  configs += [
+    ":warnings",
+    "//build/config/compiler:no_exit_time_destructors",
+  ]
 
   deps = []
   if (is_fuchsia) {
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index 1526894..3a943c3 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit 15268943dc72c67cd85764ef715a2a5f3cd403a0
+Subproject commit 3a943c302028af8cf94f53f2f7f9d7c884a7ce05
diff --git a/third_party/pdfium b/third_party/pdfium
index 2015932..7f80ad7 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit 20159328af8ccaedc7c8963b0d247d28631000df
+Subproject commit 7f80ad7406e307600914d4ba6ac429cb556df9a3
diff --git a/third_party/perfetto b/third_party/perfetto
index edd70a1..ceb75fb 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit edd70a17a1fdc811de00869e4e6aa6cbef92b58f
+Subproject commit ceb75fb568cc0f3a1897aa31becb79e26f6ef67d
diff --git a/third_party/re2/src b/third_party/re2/src
index ade723c..6e8f5be 160000
--- a/third_party/re2/src
+++ b/third_party/re2/src
@@ -1 +1 @@
-Subproject commit ade723c0c3bb1961885e70ff865d211470d477a4
+Subproject commit 6e8f5be3a392c00892c1fae1e90495fb9d2cbf30
diff --git a/third_party/rust/adler2/v2/BUILD.gn b/third_party/rust/adler2/v2/BUILD.gn
index 3bcc97de..bd547adc 100644
--- a/third_party/rust/adler2/v2/BUILD.gn
+++ b/third_party/rust/adler2/v2/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_name = "adler2"
   cargo_pkg_description =
       "A simple clean-room implementation of the Adler-32 checksum"
+  cargo_pkg_repository = "https://github.com/oyvindln/adler2"
   cargo_pkg_version = "2.0.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/anstyle/v1/BUILD.gn b/third_party/rust/anstyle/v1/BUILD.gn
index a0cb345e..414ab99 100644
--- a/third_party/rust/anstyle/v1/BUILD.gn
+++ b/third_party/rust/anstyle/v1/BUILD.gn
@@ -28,6 +28,7 @@
   edition = "2021"
   cargo_pkg_name = "anstyle"
   cargo_pkg_description = "ANSI text styling"
+  cargo_pkg_repository = "https://github.com/rust-cli/anstyle.git"
   cargo_pkg_version = "1.0.11"
 
   allow_unsafe = true
diff --git a/third_party/rust/anyhow/v1/BUILD.gn b/third_party/rust/anyhow/v1/BUILD.gn
index 8408126..c9610bf9 100644
--- a/third_party/rust/anyhow/v1/BUILD.gn
+++ b/third_party/rust/anyhow/v1/BUILD.gn
@@ -36,6 +36,7 @@
   cargo_pkg_name = "anyhow"
   cargo_pkg_description =
       "Flexible concrete Error type built on std::error::Error"
+  cargo_pkg_repository = "https://github.com/dtolnay/anyhow"
   cargo_pkg_version = "1.0.98"
 
   allow_unsafe = true
diff --git a/third_party/rust/arrayvec/v0_7/BUILD.gn b/third_party/rust/arrayvec/v0_7/BUILD.gn
index cf0742f..200f976 100644
--- a/third_party/rust/arrayvec/v0_7/BUILD.gn
+++ b/third_party/rust/arrayvec/v0_7/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_authors = "bluss"
   cargo_pkg_name = "arrayvec"
   cargo_pkg_description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
+  cargo_pkg_repository = "https://github.com/bluss/arrayvec"
   cargo_pkg_version = "0.7.6"
 
   allow_unsafe = true
diff --git a/third_party/rust/autocfg/v1/BUILD.gn b/third_party/rust/autocfg/v1/BUILD.gn
index b4d715c..15c3a2e 100644
--- a/third_party/rust/autocfg/v1/BUILD.gn
+++ b/third_party/rust/autocfg/v1/BUILD.gn
@@ -28,6 +28,7 @@
   cargo_pkg_authors = "Josh Stone <cuviper@gmail.com>"
   cargo_pkg_name = "autocfg"
   cargo_pkg_description = "Automatic cfg for Rust compiler features"
+  cargo_pkg_repository = "https://github.com/cuviper/autocfg"
   cargo_pkg_version = "1.5.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/base64/v0_22/BUILD.gn b/third_party/rust/base64/v0_22/BUILD.gn
index 8544dd6..b0c6edb 100644
--- a/third_party/rust/base64/v0_22/BUILD.gn
+++ b/third_party/rust/base64/v0_22/BUILD.gn
@@ -44,6 +44,7 @@
   cargo_pkg_authors = "Marshall Pierce <marshall@mpierce.org>"
   cargo_pkg_name = "base64"
   cargo_pkg_description = "encodes and decodes base64 as bytes or utf8"
+  cargo_pkg_repository = "https://github.com/marshallpierce/rust-base64"
   cargo_pkg_version = "0.22.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/bitflags/v1/BUILD.gn b/third_party/rust/bitflags/v1/BUILD.gn
index 0de3c452..e1ca316 100644
--- a/third_party/rust/bitflags/v1/BUILD.gn
+++ b/third_party/rust/bitflags/v1/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_name = "bitflags"
   cargo_pkg_description =
       "A macro to generate structures which behave like bitflags."
+  cargo_pkg_repository = "https://github.com/bitflags/bitflags"
   cargo_pkg_version = "1.3.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/bitflags/v2/BUILD.gn b/third_party/rust/bitflags/v2/BUILD.gn
index 17affe7..77b651b 100644
--- a/third_party/rust/bitflags/v2/BUILD.gn
+++ b/third_party/rust/bitflags/v2/BUILD.gn
@@ -64,6 +64,7 @@
   cargo_pkg_name = "bitflags"
   cargo_pkg_description =
       "A macro to generate structures which behave like bitflags."
+  cargo_pkg_repository = "https://github.com/bitflags/bitflags"
   cargo_pkg_version = "2.9.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/bytemuck/v1/BUILD.gn b/third_party/rust/bytemuck/v1/BUILD.gn
index a7ab6b75..3a2e3b74 100644
--- a/third_party/rust/bytemuck/v1/BUILD.gn
+++ b/third_party/rust/bytemuck/v1/BUILD.gn
@@ -37,6 +37,7 @@
   cargo_pkg_authors = "Lokathor <zefria@gmail.com>"
   cargo_pkg_name = "bytemuck"
   cargo_pkg_description = "A crate for mucking around with piles of bytes."
+  cargo_pkg_repository = "https://github.com/Lokathor/bytemuck"
   cargo_pkg_version = "1.23.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/bytemuck_derive/v1/BUILD.gn b/third_party/rust/bytemuck_derive/v1/BUILD.gn
index 2ebecad..21f0d52 100644
--- a/third_party/rust/bytemuck_derive/v1/BUILD.gn
+++ b/third_party/rust/bytemuck_derive/v1/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "Lokathor <zefria@gmail.com>"
   cargo_pkg_name = "bytemuck_derive"
   cargo_pkg_description = "derive proc-macros for `bytemuck`"
+  cargo_pkg_repository = "https://github.com/Lokathor/bytemuck"
   cargo_pkg_version = "1.9.3"
 
   allow_unsafe = false
diff --git a/third_party/rust/bytes/v1/BUILD.gn b/third_party/rust/bytes/v1/BUILD.gn
index 13573fe..b35c13be 100644
--- a/third_party/rust/bytes/v1/BUILD.gn
+++ b/third_party/rust/bytes/v1/BUILD.gn
@@ -43,6 +43,7 @@
       "Carl Lerche <me@carllerche.com>, Sean McArthur <sean@seanmonstar.com>"
   cargo_pkg_name = "bytes"
   cargo_pkg_description = "Types and traits for working with bytes"
+  cargo_pkg_repository = "https://github.com/tokio-rs/bytes"
   cargo_pkg_version = "1.10.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/calendrical_calculations/v0_2/BUILD.gn b/third_party/rust/calendrical_calculations/v0_2/BUILD.gn
index 359aadb..2d074f3 100644
--- a/third_party/rust/calendrical_calculations/v0_2/BUILD.gn
+++ b/third_party/rust/calendrical_calculations/v0_2/BUILD.gn
@@ -36,6 +36,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "calendrical_calculations"
   cargo_pkg_description = "Calendrical calculations in Rust"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.2.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/cfg_if/v1/BUILD.gn b/third_party/rust/cfg_if/v1/BUILD.gn
index 0ba91d8..5a53970 100644
--- a/third_party/rust/cfg_if/v1/BUILD.gn
+++ b/third_party/rust/cfg_if/v1/BUILD.gn
@@ -23,6 +23,7 @@
   cargo_pkg_authors = "Alex Crichton <alex@alexcrichton.com>"
   cargo_pkg_name = "cfg-if"
   cargo_pkg_description = "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted."
+  cargo_pkg_repository = "https://github.com/rust-lang/cfg-if"
   cargo_pkg_version = "1.0.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/chromium_crates_io/BUILD.gn.hbs b/third_party/rust/chromium_crates_io/BUILD.gn.hbs
index b133b5a..4e1eae63 100644
--- a/third_party/rust/chromium_crates_io/BUILD.gn.hbs
+++ b/third_party/rust/chromium_crates_io/BUILD.gn.hbs
@@ -46,6 +46,11 @@
       cargo_pkg_description = "{{gn_escape this}}"
     {{/with}}
   {{/if}}
+  {{#if cargo_pkg_repository}}
+    {{#with cargo_pkg_repository}}
+      cargo_pkg_repository = "{{this}}"
+    {{/with}}
+  {{/if}}
   cargo_pkg_version = "{{cargo_pkg_version}}"
 
   {{! `cargo_pkg_version` changes during minor version updates, so (to help
diff --git a/third_party/rust/clap/v4/BUILD.gn b/third_party/rust/clap/v4/BUILD.gn
index fa04084..d05fa45 100644
--- a/third_party/rust/clap/v4/BUILD.gn
+++ b/third_party/rust/clap/v4/BUILD.gn
@@ -153,6 +153,7 @@
   edition = "2021"
   cargo_pkg_name = "clap"
   cargo_pkg_description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
+  cargo_pkg_repository = "https://github.com/clap-rs/clap"
   cargo_pkg_version = "4.5.41"
 
   allow_unsafe = false
diff --git a/third_party/rust/clap_builder/v4/BUILD.gn b/third_party/rust/clap_builder/v4/BUILD.gn
index e5a95cc..cc0efbda 100644
--- a/third_party/rust/clap_builder/v4/BUILD.gn
+++ b/third_party/rust/clap_builder/v4/BUILD.gn
@@ -78,6 +78,7 @@
   edition = "2021"
   cargo_pkg_name = "clap_builder"
   cargo_pkg_description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
+  cargo_pkg_repository = "https://github.com/clap-rs/clap"
   cargo_pkg_version = "4.5.41"
 
   allow_unsafe = false
diff --git a/third_party/rust/clap_lex/v0_7/BUILD.gn b/third_party/rust/clap_lex/v0_7/BUILD.gn
index d391638..e75cfb3 100644
--- a/third_party/rust/clap_lex/v0_7/BUILD.gn
+++ b/third_party/rust/clap_lex/v0_7/BUILD.gn
@@ -24,6 +24,7 @@
   edition = "2021"
   cargo_pkg_name = "clap_lex"
   cargo_pkg_description = "Minimal, flexible command line parser"
+  cargo_pkg_repository = "https://github.com/clap-rs/clap"
   cargo_pkg_version = "0.7.5"
 
   allow_unsafe = true
diff --git a/third_party/rust/codespan_reporting/v0_12/BUILD.gn b/third_party/rust/codespan_reporting/v0_12/BUILD.gn
index 849105a..f3cd27ad 100644
--- a/third_party/rust/codespan_reporting/v0_12/BUILD.gn
+++ b/third_party/rust/codespan_reporting/v0_12/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_name = "codespan-reporting"
   cargo_pkg_description =
       "Beautiful diagnostic reporting for text-based programming languages"
+  cargo_pkg_repository = "https://github.com/brendanzab/codespan"
   cargo_pkg_version = "0.12.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/combine/v4/BUILD.gn b/third_party/rust/combine/v4/BUILD.gn
index 16e9f3f..3cb77a75 100644
--- a/third_party/rust/combine/v4/BUILD.gn
+++ b/third_party/rust/combine/v4/BUILD.gn
@@ -48,6 +48,7 @@
   cargo_pkg_name = "combine"
   cargo_pkg_description =
       "Fast parser combinators on arbitrary streams with zero-copy support."
+  cargo_pkg_repository = "https://github.com/Marwes/combine"
   cargo_pkg_version = "4.6.7"
 
   allow_unsafe = true
diff --git a/third_party/rust/core_maths/v0_1/BUILD.gn b/third_party/rust/core_maths/v0_1/BUILD.gn
index 98c52d0..6c6d716 100644
--- a/third_party/rust/core_maths/v0_1/BUILD.gn
+++ b/third_party/rust/core_maths/v0_1/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "Robert Bastian <me@robertbastian.dev"
   cargo_pkg_name = "core_maths"
   cargo_pkg_description = "Extension trait for full float functionality in `#[no_std]` backed by `libm`."
+  cargo_pkg_repository = "https://github.com/robertbastian/core_maths"
   cargo_pkg_version = "0.1.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/crc32fast/v1/BUILD.gn b/third_party/rust/crc32fast/v1/BUILD.gn
index 3ae6714..9ce1512 100644
--- a/third_party/rust/crc32fast/v1/BUILD.gn
+++ b/third_party/rust/crc32fast/v1/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_name = "crc32fast"
   cargo_pkg_description =
       "Fast, SIMD-accelerated CRC32 (IEEE) checksum computation"
+  cargo_pkg_repository = "https://github.com/srijs/rust-crc32fast"
   cargo_pkg_version = "1.5.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/cxx/v1/BUILD.gn b/third_party/rust/cxx/v1/BUILD.gn
index 18936c6..269516a 100644
--- a/third_party/rust/cxx/v1/BUILD.gn
+++ b/third_party/rust/cxx/v1/BUILD.gn
@@ -53,6 +53,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "cxx"
   cargo_pkg_description = "Safe interop between Rust and C++"
+  cargo_pkg_repository = "https://github.com/dtolnay/cxx"
   cargo_pkg_version = "1.0.160"
 
   allow_unsafe = true
diff --git a/third_party/rust/cxxbridge_cmd/v1/BUILD.gn b/third_party/rust/cxxbridge_cmd/v1/BUILD.gn
index ffc3f7cb..eb1df13 100644
--- a/third_party/rust/cxxbridge_cmd/v1/BUILD.gn
+++ b/third_party/rust/cxxbridge_cmd/v1/BUILD.gn
@@ -72,6 +72,7 @@
   cargo_pkg_name = "cxxbridge-cmd"
   cargo_pkg_description =
       "C++ code generator for integrating `cxx` crate into a non-Cargo build."
+  cargo_pkg_repository = "https://github.com/dtolnay/cxx"
   cargo_pkg_version = "1.0.160"
 
   allow_unsafe = false
diff --git a/third_party/rust/cxxbridge_flags/v1/BUILD.gn b/third_party/rust/cxxbridge_flags/v1/BUILD.gn
index 6fecc026..deb0883 100644
--- a/third_party/rust/cxxbridge_flags/v1/BUILD.gn
+++ b/third_party/rust/cxxbridge_flags/v1/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_name = "cxxbridge-flags"
   cargo_pkg_description =
       "Compiler configuration of the `cxx` crate (implementation detail)"
+  cargo_pkg_repository = "https://github.com/dtolnay/cxx"
   cargo_pkg_version = "1.0.160"
 
   allow_unsafe = false
diff --git a/third_party/rust/cxxbridge_macro/v1/BUILD.gn b/third_party/rust/cxxbridge_macro/v1/BUILD.gn
index 55be0875..fef0ea2 100644
--- a/third_party/rust/cxxbridge_macro/v1/BUILD.gn
+++ b/third_party/rust/cxxbridge_macro/v1/BUILD.gn
@@ -61,6 +61,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "cxxbridge-macro"
   cargo_pkg_description = "Implementation detail of the `cxx` crate."
+  cargo_pkg_repository = "https://github.com/dtolnay/cxx"
   cargo_pkg_version = "1.0.160"
 
   allow_unsafe = false
diff --git a/third_party/rust/derivre/v0_3/BUILD.gn b/third_party/rust/derivre/v0_3/BUILD.gn
index 87a7060..4d8be6b7 100644
--- a/third_party/rust/derivre/v0_3/BUILD.gn
+++ b/third_party/rust/derivre/v0_3/BUILD.gn
@@ -37,6 +37,7 @@
   cargo_pkg_authors = "Michal Moskal <michal@moskal.me>"
   cargo_pkg_name = "derivre"
   cargo_pkg_description = "A derivative-based regular expression engine"
+  cargo_pkg_repository = "https://github.com/microsoft/derivre"
   cargo_pkg_version = "0.3.8"
 
   allow_unsafe = false
diff --git a/third_party/rust/diplomat/v0_12/BUILD.gn b/third_party/rust/diplomat/v0_12/BUILD.gn
index 489650d4..0b69e7e 100644
--- a/third_party/rust/diplomat/v0_12/BUILD.gn
+++ b/third_party/rust/diplomat/v0_12/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_authors = "Shadaj Laddad <shadaj@users.noreply.github.com>, Manish Goregaokar <manishsmail@gmail.com>, Quinn Okabayashi <QnnOkabayashi@users.noreply.github.com>"
   cargo_pkg_name = "diplomat"
   cargo_pkg_description = "The diplomat FFI generation macro"
+  cargo_pkg_repository = "https://github.com/rust-diplomat/diplomat"
   cargo_pkg_version = "0.12.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/diplomat_core/v0_12/BUILD.gn b/third_party/rust/diplomat_core/v0_12/BUILD.gn
index c8e44b3..0f049221 100644
--- a/third_party/rust/diplomat_core/v0_12/BUILD.gn
+++ b/third_party/rust/diplomat_core/v0_12/BUILD.gn
@@ -52,6 +52,7 @@
   cargo_pkg_name = "diplomat_core"
   cargo_pkg_description =
       "Shared utilities between Diplomat macros and code generation"
+  cargo_pkg_repository = "https://github.com/rust-diplomat/diplomat"
   cargo_pkg_version = "0.12.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/diplomat_runtime/v0_12/BUILD.gn b/third_party/rust/diplomat_runtime/v0_12/BUILD.gn
index 342a806d..2b9cbbf 100644
--- a/third_party/rust/diplomat_runtime/v0_12/BUILD.gn
+++ b/third_party/rust/diplomat_runtime/v0_12/BUILD.gn
@@ -28,6 +28,7 @@
   cargo_pkg_authors = "Shadaj Laddad <shadaj@users.noreply.github.com>, Manish Goregaokar <manishsmail@gmail.com>, Quinn Okabayashi <QnnOkabayashi@users.noreply.github.com>"
   cargo_pkg_name = "diplomat-runtime"
   cargo_pkg_description = "Common runtime utilities used by diplomat codegen"
+  cargo_pkg_repository = "https://github.com/rust-diplomat/diplomat"
   cargo_pkg_version = "0.12.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/displaydoc/v0_2/BUILD.gn b/third_party/rust/displaydoc/v0_2/BUILD.gn
index 8ce6626..cf2e1ee8 100644
--- a/third_party/rust/displaydoc/v0_2/BUILD.gn
+++ b/third_party/rust/displaydoc/v0_2/BUILD.gn
@@ -27,6 +27,7 @@
   cargo_pkg_authors = "Jane Lusby <jlusby@yaah.dev>"
   cargo_pkg_name = "displaydoc"
   cargo_pkg_description = "A derive macro for implementing the display Trait via a doc comment and string interpolation"
+  cargo_pkg_repository = "https://github.com/yaahc/displaydoc"
   cargo_pkg_version = "0.2.5"
 
   allow_unsafe = false
diff --git a/third_party/rust/either/v1/BUILD.gn b/third_party/rust/either/v1/BUILD.gn
index caf9a81..d3ecdb55 100644
--- a/third_party/rust/either/v1/BUILD.gn
+++ b/third_party/rust/either/v1/BUILD.gn
@@ -28,6 +28,7 @@
   cargo_pkg_authors = "bluss"
   cargo_pkg_name = "either"
   cargo_pkg_description = "The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases."
+  cargo_pkg_repository = "https://github.com/rayon-rs/either"
   cargo_pkg_version = "1.15.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/encoding_rs/v0_8/BUILD.gn b/third_party/rust/encoding_rs/v0_8/BUILD.gn
index d8326b6e..fa3585c 100644
--- a/third_party/rust/encoding_rs/v0_8/BUILD.gn
+++ b/third_party/rust/encoding_rs/v0_8/BUILD.gn
@@ -46,6 +46,7 @@
   cargo_pkg_name = "encoding_rs"
   cargo_pkg_description =
       "A Gecko-oriented implementation of the Encoding Standard"
+  cargo_pkg_repository = "https://github.com/hsivonen/encoding_rs"
   cargo_pkg_version = "0.8.35"
 
   allow_unsafe = true
diff --git a/third_party/rust/equivalent/v1/BUILD.gn b/third_party/rust/equivalent/v1/BUILD.gn
index 23092c5..7afa144 100644
--- a/third_party/rust/equivalent/v1/BUILD.gn
+++ b/third_party/rust/equivalent/v1/BUILD.gn
@@ -23,6 +23,7 @@
   edition = "2015"
   cargo_pkg_name = "equivalent"
   cargo_pkg_description = "Traits for key comparison in maps."
+  cargo_pkg_repository = "https://github.com/indexmap-rs/equivalent"
   cargo_pkg_version = "1.0.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/fdeflate/v0_3/BUILD.gn b/third_party/rust/fdeflate/v0_3/BUILD.gn
index 6d1fae5..fed6e18 100644
--- a/third_party/rust/fdeflate/v0_3/BUILD.gn
+++ b/third_party/rust/fdeflate/v0_3/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_authors = "The image-rs Developers"
   cargo_pkg_name = "fdeflate"
   cargo_pkg_description = "Fast specialized deflate implementation"
+  cargo_pkg_repository = "https://github.com/image-rs/fdeflate"
   cargo_pkg_version = "0.3.7"
 
   allow_unsafe = false
diff --git a/third_party/rust/fend_core/v1/BUILD.gn b/third_party/rust/fend_core/v1/BUILD.gn
index 629006e..5ec3d7a 100644
--- a/third_party/rust/fend_core/v1/BUILD.gn
+++ b/third_party/rust/fend_core/v1/BUILD.gn
@@ -60,6 +60,7 @@
   edition = "2024"
   cargo_pkg_name = "fend-core"
   cargo_pkg_description = "Arbitrary-precision unit-aware calculator"
+  cargo_pkg_repository = "https://github.com/printfn/fend"
   cargo_pkg_version = "1.5.7"
 
   allow_unsafe = false
diff --git a/third_party/rust/fixed_decimal/v0_7/BUILD.gn b/third_party/rust/fixed_decimal/v0_7/BUILD.gn
index 5e65845..03df93b 100644
--- a/third_party/rust/fixed_decimal/v0_7/BUILD.gn
+++ b/third_party/rust/fixed_decimal/v0_7/BUILD.gn
@@ -33,6 +33,7 @@
   cargo_pkg_name = "fixed_decimal"
   cargo_pkg_description =
       "An API for representing numbers in a human-readable form"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.7.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/flate2/v1/BUILD.gn b/third_party/rust/flate2/v1/BUILD.gn
index 481ad26..6657c3f 100644
--- a/third_party/rust/flate2/v1/BUILD.gn
+++ b/third_party/rust/flate2/v1/BUILD.gn
@@ -43,6 +43,7 @@
   cargo_pkg_authors = "Alex Crichton <alex@alexcrichton.com>, Josh Triplett <josh@joshtriplett.org>"
   cargo_pkg_name = "flate2"
   cargo_pkg_description = "DEFLATE compression and decompression exposed as Read/BufRead/Write streams. Supports miniz_oxide and multiple zlib implementations. Supports zlib, gzip, and raw deflate streams."
+  cargo_pkg_repository = "https://github.com/rust-lang/flate2-rs"
   cargo_pkg_version = "1.1.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/foldhash/v0_1/BUILD.gn b/third_party/rust/foldhash/v0_1/BUILD.gn
index 158ae774..17c7dc1 100644
--- a/third_party/rust/foldhash/v0_1/BUILD.gn
+++ b/third_party/rust/foldhash/v0_1/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_name = "foldhash"
   cargo_pkg_description =
       "A fast, non-cryptographic, minimally DoS-resistant hashing algorithm."
+  cargo_pkg_repository = "https://github.com/orlp/foldhash"
   cargo_pkg_version = "0.1.5"
 
   allow_unsafe = true
diff --git a/third_party/rust/font_types/v0_9/BUILD.gn b/third_party/rust/font_types/v0_9/BUILD.gn
index 092f68f..2ee83cfc 100644
--- a/third_party/rust/font_types/v0_9/BUILD.gn
+++ b/third_party/rust/font_types/v0_9/BUILD.gn
@@ -37,6 +37,7 @@
   edition = "2021"
   cargo_pkg_name = "font-types"
   cargo_pkg_description = "Scalar types used in fonts."
+  cargo_pkg_repository = "https://github.com/googlefonts/fontations"
   cargo_pkg_version = "0.9.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/hashbrown/v0_15/BUILD.gn b/third_party/rust/hashbrown/v0_15/BUILD.gn
index 73a328a3..4f59f94 100644
--- a/third_party/rust/hashbrown/v0_15/BUILD.gn
+++ b/third_party/rust/hashbrown/v0_15/BUILD.gn
@@ -50,6 +50,7 @@
   cargo_pkg_authors = "Amanieu d'Antras <amanieu@gmail.com>"
   cargo_pkg_name = "hashbrown"
   cargo_pkg_description = "A Rust port of Google's SwissTable hash map"
+  cargo_pkg_repository = "https://github.com/rust-lang/hashbrown"
   cargo_pkg_version = "0.15.4"
 
   allow_unsafe = true
diff --git a/third_party/rust/heck/v0_5/BUILD.gn b/third_party/rust/heck/v0_5/BUILD.gn
index 8a4563e..b4fd441 100644
--- a/third_party/rust/heck/v0_5/BUILD.gn
+++ b/third_party/rust/heck/v0_5/BUILD.gn
@@ -31,6 +31,7 @@
   edition = "2021"
   cargo_pkg_name = "heck"
   cargo_pkg_description = "heck is a case conversion library."
+  cargo_pkg_repository = "https://github.com/withoutboats/heck"
   cargo_pkg_version = "0.5.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/hex/v0_4/BUILD.gn b/third_party/rust/hex/v0_4/BUILD.gn
index 7194be4..f077e6703 100644
--- a/third_party/rust/hex/v0_4/BUILD.gn
+++ b/third_party/rust/hex/v0_4/BUILD.gn
@@ -27,6 +27,7 @@
   cargo_pkg_name = "hex"
   cargo_pkg_description =
       "Encoding and decoding data into/from hexadecimal representation."
+  cargo_pkg_repository = "https://github.com/KokaKiwi/rust-hex"
   cargo_pkg_version = "0.4.3"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_calendar/v2/BUILD.gn b/third_party/rust/icu_calendar/v2/BUILD.gn
index e094ba3..87e440c 100644
--- a/third_party/rust/icu_calendar/v2/BUILD.gn
+++ b/third_party/rust/icu_calendar/v2/BUILD.gn
@@ -55,6 +55,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_calendar"
   cargo_pkg_description = "Date APIs for Gregorian and non-Gregorian calendars"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_calendar_data/v2/BUILD.gn b/third_party/rust/icu_calendar_data/v2/BUILD.gn
index f3472e3..9e9babea 100644
--- a/third_party/rust/icu_calendar_data/v2/BUILD.gn
+++ b/third_party/rust/icu_calendar_data/v2/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_calendar_data"
   cargo_pkg_description = "Data for the icu_calendar crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_casemap/v2/BUILD.gn b/third_party/rust/icu_casemap/v2/BUILD.gn
index 0c928e1..38b0270c 100644
--- a/third_party/rust/icu_casemap/v2/BUILD.gn
+++ b/third_party/rust/icu_casemap/v2/BUILD.gn
@@ -37,6 +37,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_casemap"
   cargo_pkg_description = "Unicode case mapping and folding algorithms"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_casemap_data/v2/BUILD.gn b/third_party/rust/icu_casemap_data/v2/BUILD.gn
index 4fb796b..2e5fe48d 100644
--- a/third_party/rust/icu_casemap_data/v2/BUILD.gn
+++ b/third_party/rust/icu_casemap_data/v2/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_casemap_data"
   cargo_pkg_description = "Data for the icu_casemap crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_collections/v2/BUILD.gn b/third_party/rust/icu_collections/v2/BUILD.gn
index 89d822a7..914fcf2 100644
--- a/third_party/rust/icu_collections/v2/BUILD.gn
+++ b/third_party/rust/icu_collections/v2/BUILD.gn
@@ -39,6 +39,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_collections"
   cargo_pkg_description = "Collection of API for use in ICU libraries."
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/icu_decimal/v2/BUILD.gn b/third_party/rust/icu_decimal/v2/BUILD.gn
index 072b34c..8741a29 100644
--- a/third_party/rust/icu_decimal/v2/BUILD.gn
+++ b/third_party/rust/icu_decimal/v2/BUILD.gn
@@ -31,6 +31,7 @@
   cargo_pkg_name = "icu_decimal"
   cargo_pkg_description =
       "API for formatting basic decimal numbers in a locale-sensitive way"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_decimal_data/v2/BUILD.gn b/third_party/rust/icu_decimal_data/v2/BUILD.gn
index 67f80d68..672fbae 100644
--- a/third_party/rust/icu_decimal_data/v2/BUILD.gn
+++ b/third_party/rust/icu_decimal_data/v2/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_decimal_data"
   cargo_pkg_description = "Data for the icu_decimal crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_experimental/v0_3/BUILD.gn b/third_party/rust/icu_experimental/v0_3/BUILD.gn
index deb4fb3..e9621acb 100644
--- a/third_party/rust/icu_experimental/v0_3/BUILD.gn
+++ b/third_party/rust/icu_experimental/v0_3/BUILD.gn
@@ -118,6 +118,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_experimental"
   cargo_pkg_description = "ICU4X pre-release components under active development; all code in this crate is unstable."
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.3.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_experimental_data/v0_3/BUILD.gn b/third_party/rust/icu_experimental_data/v0_3/BUILD.gn
index 2f378802..7550da2f 100644
--- a/third_party/rust/icu_experimental_data/v0_3/BUILD.gn
+++ b/third_party/rust/icu_experimental_data/v0_3/BUILD.gn
@@ -67,6 +67,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_experimental_data"
   cargo_pkg_description = "Data for the icu_experimental crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.3.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_list/v2/BUILD.gn b/third_party/rust/icu_list/v2/BUILD.gn
index 6d628ed..0510eea 100644
--- a/third_party/rust/icu_list/v2/BUILD.gn
+++ b/third_party/rust/icu_list/v2/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_list"
   cargo_pkg_description = "ECMA-402 ListFormatter"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_list_data/v2/BUILD.gn b/third_party/rust/icu_list_data/v2/BUILD.gn
index 793a630..8189f15c 100644
--- a/third_party/rust/icu_list_data/v2/BUILD.gn
+++ b/third_party/rust/icu_list_data/v2/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_list_data"
   cargo_pkg_description = "Data for the icu_list crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_locale/v2/BUILD.gn b/third_party/rust/icu_locale/v2/BUILD.gn
index ed3cdf2..5e1daa8 100644
--- a/third_party/rust/icu_locale/v2/BUILD.gn
+++ b/third_party/rust/icu_locale/v2/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_name = "icu_locale"
   cargo_pkg_description =
       "API for Unicode Language and Locale Identifiers canonicalization"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/icu_locale_core/v2/BUILD.gn b/third_party/rust/icu_locale_core/v2/BUILD.gn
index de01f9d..0ae9b51 100644
--- a/third_party/rust/icu_locale_core/v2/BUILD.gn
+++ b/third_party/rust/icu_locale_core/v2/BUILD.gn
@@ -86,6 +86,7 @@
   cargo_pkg_name = "icu_locale_core"
   cargo_pkg_description =
       "API for managing Unicode Language and Locale Identifiers"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/icu_locale_data/v2/BUILD.gn b/third_party/rust/icu_locale_data/v2/BUILD.gn
index 3883310d..07b0bfc 100644
--- a/third_party/rust/icu_locale_data/v2/BUILD.gn
+++ b/third_party/rust/icu_locale_data/v2/BUILD.gn
@@ -34,6 +34,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_locale_data"
   cargo_pkg_description = "Data for the icu_locale crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_normalizer/v2/BUILD.gn b/third_party/rust/icu_normalizer/v2/BUILD.gn
index 6a58995..53294f0 100644
--- a/third_party/rust/icu_normalizer/v2/BUILD.gn
+++ b/third_party/rust/icu_normalizer/v2/BUILD.gn
@@ -27,6 +27,7 @@
   cargo_pkg_name = "icu_normalizer"
   cargo_pkg_description =
       "API for normalizing text into Unicode Normalization Forms"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/icu_normalizer_data/v2/BUILD.gn b/third_party/rust/icu_normalizer_data/v2/BUILD.gn
index c25f53b..2a7ab0b 100644
--- a/third_party/rust/icu_normalizer_data/v2/BUILD.gn
+++ b/third_party/rust/icu_normalizer_data/v2/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_normalizer_data"
   cargo_pkg_description = "Data for the icu_normalizer crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_pattern/v0_4/BUILD.gn b/third_party/rust/icu_pattern/v0_4/BUILD.gn
index a704fbb..3175be56 100644
--- a/third_party/rust/icu_pattern/v0_4/BUILD.gn
+++ b/third_party/rust/icu_pattern/v0_4/BUILD.gn
@@ -37,6 +37,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_pattern"
   cargo_pkg_description = "ICU pattern utilities"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.4.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/icu_plurals/v2/BUILD.gn b/third_party/rust/icu_plurals/v2/BUILD.gn
index 2c6da4b3..104b5ff 100644
--- a/third_party/rust/icu_plurals/v2/BUILD.gn
+++ b/third_party/rust/icu_plurals/v2/BUILD.gn
@@ -38,6 +38,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_plurals"
   cargo_pkg_description = "Unicode Plural Rules categorizer for numeric input"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_plurals_data/v2/BUILD.gn b/third_party/rust/icu_plurals_data/v2/BUILD.gn
index f88a5e57..0028704e 100644
--- a/third_party/rust/icu_plurals_data/v2/BUILD.gn
+++ b/third_party/rust/icu_plurals_data/v2/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_plurals_data"
   cargo_pkg_description = "Data for the icu_plurals crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_properties/v2/BUILD.gn b/third_party/rust/icu_properties/v2/BUILD.gn
index 09b4bde..b6321316 100644
--- a/third_party/rust/icu_properties/v2/BUILD.gn
+++ b/third_party/rust/icu_properties/v2/BUILD.gn
@@ -34,6 +34,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_properties"
   cargo_pkg_description = "Definitions for Unicode properties"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_properties_data/v2/BUILD.gn b/third_party/rust/icu_properties_data/v2/BUILD.gn
index 21d58e6..eda67ba 100644
--- a/third_party/rust/icu_properties_data/v2/BUILD.gn
+++ b/third_party/rust/icu_properties_data/v2/BUILD.gn
@@ -145,6 +145,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "icu_properties_data"
   cargo_pkg_description = "Data for the icu_properties crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/icu_provider/v2/BUILD.gn b/third_party/rust/icu_provider/v2/BUILD.gn
index a07be0f..d3c019a3 100644
--- a/third_party/rust/icu_provider/v2/BUILD.gn
+++ b/third_party/rust/icu_provider/v2/BUILD.gn
@@ -42,6 +42,7 @@
   cargo_pkg_name = "icu_provider"
   cargo_pkg_description =
       "Trait and struct definitions for the ICU data provider"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/indexmap/v2/BUILD.gn b/third_party/rust/indexmap/v2/BUILD.gn
index 1c47cb1..069eb1f 100644
--- a/third_party/rust/indexmap/v2/BUILD.gn
+++ b/third_party/rust/indexmap/v2/BUILD.gn
@@ -47,6 +47,7 @@
   cargo_pkg_name = "indexmap"
   cargo_pkg_description =
       "A hash table with consistent order and fast iteration."
+  cargo_pkg_repository = "https://github.com/indexmap-rs/indexmap"
   cargo_pkg_version = "2.10.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/itertools/v0_11/BUILD.gn b/third_party/rust/itertools/v0_11/BUILD.gn
index 156e883d..4b9e0a9 100644
--- a/third_party/rust/itertools/v0_11/BUILD.gn
+++ b/third_party/rust/itertools/v0_11/BUILD.gn
@@ -72,6 +72,7 @@
   cargo_pkg_name = "itertools"
   cargo_pkg_description =
       "Extra iterator adaptors, iterator methods, free functions, and macros."
+  cargo_pkg_repository = "https://github.com/rust-itertools/itertools"
   cargo_pkg_version = "0.11.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/itoa/v1/BUILD.gn b/third_party/rust/itoa/v1/BUILD.gn
index 5e030ac2..6dc25a82 100644
--- a/third_party/rust/itoa/v1/BUILD.gn
+++ b/third_party/rust/itoa/v1/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "itoa"
   cargo_pkg_description = "Fast integer primitive to string conversion"
+  cargo_pkg_repository = "https://github.com/dtolnay/itoa"
   cargo_pkg_version = "1.0.15"
 
   allow_unsafe = true
diff --git a/third_party/rust/ixdtf/v0_6/BUILD.gn b/third_party/rust/ixdtf/v0_6/BUILD.gn
index 97ad8aaf..c94c873 100644
--- a/third_party/rust/ixdtf/v0_6/BUILD.gn
+++ b/third_party/rust/ixdtf/v0_6/BUILD.gn
@@ -35,6 +35,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "ixdtf"
   cargo_pkg_description = "Parser for Internet eXtended DateTime Format"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.6.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/jiff_tzdb/v0_1/BUILD.gn b/third_party/rust/jiff_tzdb/v0_1/BUILD.gn
index b26bd8a..30cc4204 100644
--- a/third_party/rust/jiff_tzdb/v0_1/BUILD.gn
+++ b/third_party/rust/jiff_tzdb/v0_1/BUILD.gn
@@ -31,6 +31,7 @@
   cargo_pkg_name = "jiff-tzdb"
   cargo_pkg_description =
       "The entire Time Zone Database embedded into your binary."
+  cargo_pkg_repository = "https://github.com/BurntSushi/jiff"
   cargo_pkg_version = "0.1.4"
 
   allow_unsafe = false
diff --git a/third_party/rust/lazy_static/v1/BUILD.gn b/third_party/rust/lazy_static/v1/BUILD.gn
index 18a1a98..5e21f16 100644
--- a/third_party/rust/lazy_static/v1/BUILD.gn
+++ b/third_party/rust/lazy_static/v1/BUILD.gn
@@ -27,6 +27,7 @@
   cargo_pkg_name = "lazy_static"
   cargo_pkg_description =
       "A macro for declaring lazily evaluated statics in Rust."
+  cargo_pkg_repository = "https://github.com/rust-lang-nursery/lazy-static.rs"
   cargo_pkg_version = "1.5.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/libc/v0_2/BUILD.gn b/third_party/rust/libc/v0_2/BUILD.gn
index 7e618ec..6ab1aa3 100644
--- a/third_party/rust/libc/v0_2/BUILD.gn
+++ b/third_party/rust/libc/v0_2/BUILD.gn
@@ -203,6 +203,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "libc"
   cargo_pkg_description = "Raw FFI bindings to platform libraries like libc."
+  cargo_pkg_repository = "https://github.com/rust-lang/libc"
   cargo_pkg_version = "0.2.174"
 
   allow_unsafe = true
diff --git a/third_party/rust/libm/v0_2/BUILD.gn b/third_party/rust/libm/v0_2/BUILD.gn
index a853a1dd..d6bba6a 100644
--- a/third_party/rust/libm/v0_2/BUILD.gn
+++ b/third_party/rust/libm/v0_2/BUILD.gn
@@ -197,6 +197,7 @@
   cargo_pkg_authors = "Jorge Aparicio <jorge@japaric.io>"
   cargo_pkg_name = "libm"
   cargo_pkg_description = "libm in pure Rust"
+  cargo_pkg_repository = "https://github.com/rust-lang/compiler-builtins"
   cargo_pkg_version = "0.2.15"
 
   allow_unsafe = true
diff --git a/third_party/rust/litemap/v0_8/BUILD.gn b/third_party/rust/litemap/v0_8/BUILD.gn
index 9b4699a..7534ad0 100644
--- a/third_party/rust/litemap/v0_8/BUILD.gn
+++ b/third_party/rust/litemap/v0_8/BUILD.gn
@@ -33,6 +33,7 @@
   cargo_pkg_name = "litemap"
   cargo_pkg_description =
       "A key-value Map implementation based on a flat, sorted Vec."
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.8.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/llguidance/v1/BUILD.gn b/third_party/rust/llguidance/v1/BUILD.gn
index 882620ce..98410b5 100644
--- a/third_party/rust/llguidance/v1/BUILD.gn
+++ b/third_party/rust/llguidance/v1/BUILD.gn
@@ -68,6 +68,7 @@
   edition = "2021"
   cargo_pkg_name = "llguidance"
   cargo_pkg_description = "Super-fast Structured Outputs"
+  cargo_pkg_repository = "https://github.com/guidance-ai/llguidance"
   cargo_pkg_version = "1.0.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/log/v0_4/BUILD.gn b/third_party/rust/log/v0_4/BUILD.gn
index 8d4d70a..e86ff35 100644
--- a/third_party/rust/log/v0_4/BUILD.gn
+++ b/third_party/rust/log/v0_4/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "log"
   cargo_pkg_description = "A lightweight logging facade for Rust"
+  cargo_pkg_repository = "https://github.com/rust-lang/log"
   cargo_pkg_version = "0.4.27"
 
   allow_unsafe = true
diff --git a/third_party/rust/memchr/v2/BUILD.gn b/third_party/rust/memchr/v2/BUILD.gn
index d879b81..c4ce0b7 100644
--- a/third_party/rust/memchr/v2/BUILD.gn
+++ b/third_party/rust/memchr/v2/BUILD.gn
@@ -68,6 +68,7 @@
   cargo_pkg_authors = "Andrew Gallant <jamslam@gmail.com>, bluss"
   cargo_pkg_name = "memchr"
   cargo_pkg_description = "Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for 1, 2 or 3 byte search and single substring search."
+  cargo_pkg_repository = "https://github.com/BurntSushi/memchr"
   cargo_pkg_version = "2.7.5"
 
   allow_unsafe = true
diff --git a/third_party/rust/miniz_oxide/v0_8/BUILD.gn b/third_party/rust/miniz_oxide/v0_8/BUILD.gn
index fff258f0..06e26ce 100644
--- a/third_party/rust/miniz_oxide/v0_8/BUILD.gn
+++ b/third_party/rust/miniz_oxide/v0_8/BUILD.gn
@@ -37,6 +37,8 @@
   cargo_pkg_authors = "Frommi <daniil.liferenko@gmail.com>, oyvindln <oyvindln@users.noreply.github.com>, Rich Geldreich richgel99@gmail.com"
   cargo_pkg_name = "miniz_oxide"
   cargo_pkg_description = "DEFLATE compression and decompression library rewritten in Rust based on miniz"
+  cargo_pkg_repository =
+      "https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide"
   cargo_pkg_version = "0.8.9"
 
   allow_unsafe = false
diff --git a/third_party/rust/num_bigint/v0_4/BUILD.gn b/third_party/rust/num_bigint/v0_4/BUILD.gn
index 48bf24a0..62a09078 100644
--- a/third_party/rust/num_bigint/v0_4/BUILD.gn
+++ b/third_party/rust/num_bigint/v0_4/BUILD.gn
@@ -50,6 +50,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "num-bigint"
   cargo_pkg_description = "Big integer implementation for Rust"
+  cargo_pkg_repository = "https://github.com/rust-num/num-bigint"
   cargo_pkg_version = "0.4.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/num_integer/v0_1/BUILD.gn b/third_party/rust/num_integer/v0_1/BUILD.gn
index f2ba05f9..09a92ee 100644
--- a/third_party/rust/num_integer/v0_1/BUILD.gn
+++ b/third_party/rust/num_integer/v0_1/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "num-integer"
   cargo_pkg_description = "Integer traits and functions"
+  cargo_pkg_repository = "https://github.com/rust-num/num-integer"
   cargo_pkg_version = "0.1.46"
 
   allow_unsafe = false
diff --git a/third_party/rust/num_rational/v0_4/BUILD.gn b/third_party/rust/num_rational/v0_4/BUILD.gn
index 2b762a9..e406498 100644
--- a/third_party/rust/num_rational/v0_4/BUILD.gn
+++ b/third_party/rust/num_rational/v0_4/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "num-rational"
   cargo_pkg_description = "Rational numbers implementation for Rust"
+  cargo_pkg_repository = "https://github.com/rust-num/num-rational"
   cargo_pkg_version = "0.4.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/num_traits/v0_2/BUILD.gn b/third_party/rust/num_traits/v0_2/BUILD.gn
index fd27af8..00f46bf 100644
--- a/third_party/rust/num_traits/v0_2/BUILD.gn
+++ b/third_party/rust/num_traits/v0_2/BUILD.gn
@@ -42,6 +42,7 @@
   cargo_pkg_authors = "The Rust Project Developers"
   cargo_pkg_name = "num-traits"
   cargo_pkg_description = "Numeric traits for generic mathematics"
+  cargo_pkg_repository = "https://github.com/rust-num/num-traits"
   cargo_pkg_version = "0.2.19"
 
   allow_unsafe = true
diff --git a/third_party/rust/png/v0_18/BUILD.gn b/third_party/rust/png/v0_18/BUILD.gn
index fb9a398..c39858a 100644
--- a/third_party/rust/png/v0_18/BUILD.gn
+++ b/third_party/rust/png/v0_18/BUILD.gn
@@ -42,6 +42,7 @@
   cargo_pkg_authors = "The image-rs Developers"
   cargo_pkg_name = "png"
   cargo_pkg_description = "PNG decoding and encoding library in pure Rust"
+  cargo_pkg_repository = "https://github.com/image-rs/image-png"
   cargo_pkg_version = "0.18.0-rc"
 
   allow_unsafe = false
diff --git a/third_party/rust/potential_utf/v0_1/BUILD.gn b/third_party/rust/potential_utf/v0_1/BUILD.gn
index 3a237d0..fd24da45 100644
--- a/third_party/rust/potential_utf/v0_1/BUILD.gn
+++ b/third_party/rust/potential_utf/v0_1/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "potential_utf"
   cargo_pkg_description = "Unvalidated string and character types"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.1.2"
 
   allow_unsafe = true
diff --git a/third_party/rust/proc_macro2/v1/BUILD.gn b/third_party/rust/proc_macro2/v1/BUILD.gn
index a94a8612..41ee017 100644
--- a/third_party/rust/proc_macro2/v1/BUILD.gn
+++ b/third_party/rust/proc_macro2/v1/BUILD.gn
@@ -33,6 +33,7 @@
       "David Tolnay <dtolnay@gmail.com>, Alex Crichton <alex@alexcrichton.com>"
   cargo_pkg_name = "proc-macro2"
   cargo_pkg_description = "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case."
+  cargo_pkg_repository = "https://github.com/dtolnay/proc-macro2"
   cargo_pkg_version = "1.0.95"
 
   allow_unsafe = true
diff --git a/third_party/rust/prost/v0_14/BUILD.gn b/third_party/rust/prost/v0_14/BUILD.gn
index 4de7b952..d5075d0 100644
--- a/third_party/rust/prost/v0_14/BUILD.gn
+++ b/third_party/rust/prost/v0_14/BUILD.gn
@@ -35,6 +35,7 @@
   cargo_pkg_name = "prost"
   cargo_pkg_description =
       "A Protocol Buffers implementation for the Rust Language."
+  cargo_pkg_repository = "https://github.com/tokio-rs/prost"
   cargo_pkg_version = "0.14.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/prost_derive/v0_14/BUILD.gn b/third_party/rust/prost_derive/v0_14/BUILD.gn
index 37e99cb..bd2d691 100644
--- a/third_party/rust/prost_derive/v0_14/BUILD.gn
+++ b/third_party/rust/prost_derive/v0_14/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_authors = "Dan Burkert <dan@danburkert.com>, Lucio Franco <luciofranco14@gmail.com>, Casper Meijn <casper@meijn.net>, Tokio Contributors <team@tokio.rs>"
   cargo_pkg_name = "prost-derive"
   cargo_pkg_description = "Generate encoding and decoding implementations for Prost annotated types."
+  cargo_pkg_repository = "https://github.com/tokio-rs/prost"
   cargo_pkg_version = "0.14.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/qr_code/v2/BUILD.gn b/third_party/rust/qr_code/v2/BUILD.gn
index ca255e4..c6151a7 100644
--- a/third_party/rust/qr_code/v2/BUILD.gn
+++ b/third_party/rust/qr_code/v2/BUILD.gn
@@ -37,6 +37,7 @@
   cargo_pkg_authors = "kennytm <kennytm@gmail.com>, Riccardo Casatta <riccardo.casatta@gmail.com>"
   cargo_pkg_name = "qr_code"
   cargo_pkg_description = "QR code encoder in Rust, support structured append (data in multiple qrcodes)"
+  cargo_pkg_repository = "https://github.com/RCasatta/qr_code"
   cargo_pkg_version = "2.0.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/quote/v1/BUILD.gn b/third_party/rust/quote/v1/BUILD.gn
index 55faea9..9cf7854 100644
--- a/third_party/rust/quote/v1/BUILD.gn
+++ b/third_party/rust/quote/v1/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "quote"
   cargo_pkg_description = "Quasi-quoting macro quote!(...)"
+  cargo_pkg_repository = "https://github.com/dtolnay/quote"
   cargo_pkg_version = "1.0.40"
 
   allow_unsafe = false
diff --git a/third_party/rust/read_fonts/v0_30/BUILD.gn b/third_party/rust/read_fonts/v0_30/BUILD.gn
index 4d7856d..a222a0ce 100644
--- a/third_party/rust/read_fonts/v0_30/BUILD.gn
+++ b/third_party/rust/read_fonts/v0_30/BUILD.gn
@@ -179,6 +179,7 @@
   edition = "2021"
   cargo_pkg_name = "read-fonts"
   cargo_pkg_description = "Reading OpenType font files."
+  cargo_pkg_repository = "https://github.com/googlefonts/fontations"
   cargo_pkg_version = "0.30.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/regex_automata/v0_4/BUILD.gn b/third_party/rust/regex_automata/v0_4/BUILD.gn
index f69a57b..c66e03e 100644
--- a/third_party/rust/regex_automata/v0_4/BUILD.gn
+++ b/third_party/rust/regex_automata/v0_4/BUILD.gn
@@ -94,6 +94,8 @@
   cargo_pkg_name = "regex-automata"
   cargo_pkg_description =
       "Automata construction and matching using regular expressions."
+  cargo_pkg_repository =
+      "https://github.com/rust-lang/regex/tree/master/regex-automata"
   cargo_pkg_version = "0.4.9"
 
   allow_unsafe = false
diff --git a/third_party/rust/regex_syntax/v0_8/BUILD.gn b/third_party/rust/regex_syntax/v0_8/BUILD.gn
index 33bf228..fff237be 100644
--- a/third_party/rust/regex_syntax/v0_8/BUILD.gn
+++ b/third_party/rust/regex_syntax/v0_8/BUILD.gn
@@ -56,6 +56,8 @@
       "The Rust Project Developers, Andrew Gallant <jamslam@gmail.com>"
   cargo_pkg_name = "regex-syntax"
   cargo_pkg_description = "A regular expression parser."
+  cargo_pkg_repository =
+      "https://github.com/rust-lang/regex/tree/master/regex-syntax"
   cargo_pkg_version = "0.8.5"
 
   allow_unsafe = false
diff --git a/third_party/rust/rustc_demangle/v0_1/BUILD.gn b/third_party/rust/rustc_demangle/v0_1/BUILD.gn
index fc90a57..d08d84f8 100644
--- a/third_party/rust/rustc_demangle/v0_1/BUILD.gn
+++ b/third_party/rust/rustc_demangle/v0_1/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_authors = "Alex Crichton <alex@alexcrichton.com>"
   cargo_pkg_name = "rustc-demangle"
   cargo_pkg_description = "Rust compiler symbol demangling."
+  cargo_pkg_repository = "https://github.com/rust-lang/rustc-demangle"
   cargo_pkg_version = "0.1.25"
 
   allow_unsafe = false
diff --git a/third_party/rust/rustc_demangle_capi/v0_1/BUILD.gn b/third_party/rust/rustc_demangle_capi/v0_1/BUILD.gn
index 142c87017..11458e9f 100644
--- a/third_party/rust/rustc_demangle_capi/v0_1/BUILD.gn
+++ b/third_party/rust/rustc_demangle_capi/v0_1/BUILD.gn
@@ -21,6 +21,7 @@
   cargo_pkg_authors = "Torste Aikio <zokier@gmail.com>"
   cargo_pkg_name = "rustc-demangle-capi"
   cargo_pkg_description = "C API for the `rustc-demangle` crate"
+  cargo_pkg_repository = "https://github.com/alexcrichton/rustc-demangle"
   cargo_pkg_version = "0.1.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/rustversion/v1/BUILD.gn b/third_party/rust/rustversion/v1/BUILD.gn
index 0be2b58..31ffd29 100644
--- a/third_party/rust/rustversion/v1/BUILD.gn
+++ b/third_party/rust/rustversion/v1/BUILD.gn
@@ -37,6 +37,7 @@
   cargo_pkg_name = "rustversion"
   cargo_pkg_description =
       "Conditional compilation according to rustc compiler version"
+  cargo_pkg_repository = "https://github.com/dtolnay/rustversion"
   cargo_pkg_version = "1.0.21"
 
   allow_unsafe = false
diff --git a/third_party/rust/ryu/v1/BUILD.gn b/third_party/rust/ryu/v1/BUILD.gn
index db25722..be15ff5 100644
--- a/third_party/rust/ryu/v1/BUILD.gn
+++ b/third_party/rust/ryu/v1/BUILD.gn
@@ -38,6 +38,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "ryu"
   cargo_pkg_description = "Fast floating point to string conversion"
+  cargo_pkg_repository = "https://github.com/dtolnay/ryu"
   cargo_pkg_version = "1.0.20"
 
   allow_unsafe = true
diff --git a/third_party/rust/serde/v1/BUILD.gn b/third_party/rust/serde/v1/BUILD.gn
index ee2cca78..930cd00 100644
--- a/third_party/rust/serde/v1/BUILD.gn
+++ b/third_party/rust/serde/v1/BUILD.gn
@@ -42,6 +42,7 @@
   cargo_pkg_authors = "Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "serde"
   cargo_pkg_description = "A generic serialization/deserialization framework"
+  cargo_pkg_repository = "https://github.com/serde-rs/serde"
   cargo_pkg_version = "1.0.219"
 
   allow_unsafe = true
diff --git a/third_party/rust/serde_derive/v1/BUILD.gn b/third_party/rust/serde_derive/v1/BUILD.gn
index 958a573..e6befdb 100644
--- a/third_party/rust/serde_derive/v1/BUILD.gn
+++ b/third_party/rust/serde_derive/v1/BUILD.gn
@@ -42,6 +42,7 @@
   cargo_pkg_name = "serde_derive"
   cargo_pkg_description =
       "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
+  cargo_pkg_repository = "https://github.com/serde-rs/serde"
   cargo_pkg_version = "1.0.219"
 
   allow_unsafe = false
diff --git a/third_party/rust/serde_json/v1/BUILD.gn b/third_party/rust/serde_json/v1/BUILD.gn
index 94d2e43..dc4e87a 100644
--- a/third_party/rust/serde_json/v1/BUILD.gn
+++ b/third_party/rust/serde_json/v1/BUILD.gn
@@ -60,6 +60,7 @@
   cargo_pkg_authors = "Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "serde_json"
   cargo_pkg_description = "A JSON serialization file format"
+  cargo_pkg_repository = "https://github.com/serde-rs/json"
   cargo_pkg_version = "1.0.140"
 
   allow_unsafe = true
diff --git a/third_party/rust/serde_json_lenient/v0_2/BUILD.gn b/third_party/rust/serde_json_lenient/v0_2/BUILD.gn
index a6a9f3d..22bd2bb 100644
--- a/third_party/rust/serde_json_lenient/v0_2/BUILD.gn
+++ b/third_party/rust/serde_json_lenient/v0_2/BUILD.gn
@@ -59,6 +59,7 @@
   cargo_pkg_authors = "Adrian Taylor <adetaylor@chromium.org>, Michael Bolin <bolinfest@gmail.com>, Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "serde_json_lenient"
   cargo_pkg_description = "A lenient JSON serialization file format"
+  cargo_pkg_repository = "https://github.com/google/serde_json_lenient"
   cargo_pkg_version = "0.2.4"
 
   allow_unsafe = true
diff --git a/third_party/rust/simd_adler32/v0_3/BUILD.gn b/third_party/rust/simd_adler32/v0_3/BUILD.gn
index 72c6c71f..9e805c48 100644
--- a/third_party/rust/simd_adler32/v0_3/BUILD.gn
+++ b/third_party/rust/simd_adler32/v0_3/BUILD.gn
@@ -33,6 +33,7 @@
   cargo_pkg_name = "simd-adler32"
   cargo_pkg_description =
       "A SIMD-accelerated Adler-32 hash algorithm implementation."
+  cargo_pkg_repository = "https://github.com/mcountryman/simd-adler32"
   cargo_pkg_version = "0.3.7"
 
   allow_unsafe = true
diff --git a/third_party/rust/skrifa/v0_32/BUILD.gn b/third_party/rust/skrifa/v0_32/BUILD.gn
index fd7510ba..977e0546 100644
--- a/third_party/rust/skrifa/v0_32/BUILD.gn
+++ b/third_party/rust/skrifa/v0_32/BUILD.gn
@@ -103,6 +103,7 @@
   edition = "2021"
   cargo_pkg_name = "skrifa"
   cargo_pkg_description = "Metadata reader and glyph scaler for OpenType fonts."
+  cargo_pkg_repository = "https://github.com/googlefonts/fontations"
   cargo_pkg_version = "0.32.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/small_ctor/v0_1/BUILD.gn b/third_party/rust/small_ctor/v0_1/BUILD.gn
index bba1820..dae3b14d 100644
--- a/third_party/rust/small_ctor/v0_1/BUILD.gn
+++ b/third_party/rust/small_ctor/v0_1/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "Armin Ronacher <armin.ronacher@active-4.com>"
   cargo_pkg_name = "small_ctor"
   cargo_pkg_description = "A minimal, dependency free version of the ctor crate"
+  cargo_pkg_repository = "https://github.com/mitsuhiko/small-ctor"
   cargo_pkg_version = "0.1.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/smallvec/v1/BUILD.gn b/third_party/rust/smallvec/v1/BUILD.gn
index 906dd51..dfd23ee 100644
--- a/third_party/rust/smallvec/v1/BUILD.gn
+++ b/third_party/rust/smallvec/v1/BUILD.gn
@@ -27,6 +27,7 @@
   cargo_pkg_authors = "The Servo Project Developers"
   cargo_pkg_name = "smallvec"
   cargo_pkg_description = "'Small vector' optimization: store up to a small number of items on the stack"
+  cargo_pkg_repository = "https://github.com/servo/rust-smallvec"
   cargo_pkg_version = "1.15.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/stable_deref_trait/v1/BUILD.gn b/third_party/rust/stable_deref_trait/v1/BUILD.gn
index cb86545..067a582 100644
--- a/third_party/rust/stable_deref_trait/v1/BUILD.gn
+++ b/third_party/rust/stable_deref_trait/v1/BUILD.gn
@@ -21,6 +21,7 @@
   cargo_pkg_authors = "Robert Grosse <n210241048576@gmail.com>"
   cargo_pkg_name = "stable_deref_trait"
   cargo_pkg_description = "An unsafe marker trait for types like Box and Rc that dereference to a stable address even when moved, and hence can be used with libraries such as owning_ref and rental."
+  cargo_pkg_repository = "https://github.com/storyyeller/stable_deref_trait"
   cargo_pkg_version = "1.2.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/static_assertions/v1/BUILD.gn b/third_party/rust/static_assertions/v1/BUILD.gn
index a8875b64..0710971 100644
--- a/third_party/rust/static_assertions/v1/BUILD.gn
+++ b/third_party/rust/static_assertions/v1/BUILD.gn
@@ -33,6 +33,7 @@
   cargo_pkg_name = "static_assertions"
   cargo_pkg_description =
       "Compile-time assertions to ensure that invariants are met."
+  cargo_pkg_repository = "https://github.com/nvzqz/static-assertions-rs"
   cargo_pkg_version = "1.1.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/strck/v1/BUILD.gn b/third_party/rust/strck/v1/BUILD.gn
index 9a82cb4..cfb86a92 100644
--- a/third_party/rust/strck/v1/BUILD.gn
+++ b/third_party/rust/strck/v1/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_authors = "Quinn Okabayashi <quinnokabayashi@gmail.com>"
   cargo_pkg_name = "strck"
   cargo_pkg_description = "Checked owned and borrowed strings"
+  cargo_pkg_repository = "https://github.com/QnnOkabayashi/strck"
   cargo_pkg_version = "1.0.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/strsim/v0_11/BUILD.gn b/third_party/rust/strsim/v0_11/BUILD.gn
index 4ad9cf3..03f805c 100644
--- a/third_party/rust/strsim/v0_11/BUILD.gn
+++ b/third_party/rust/strsim/v0_11/BUILD.gn
@@ -24,6 +24,7 @@
       "Danny Guo <danny@dannyguo.com>, maxbachmann <oss@maxbachmann.de>"
   cargo_pkg_name = "strsim"
   cargo_pkg_description = "Implementations of string similarity metrics. Includes Hamming, Levenshtein, OSA, Damerau-Levenshtein, Jaro, Jaro-Winkler, and Sørensen-Dice."
+  cargo_pkg_repository = "https://github.com/rapidfuzz/strsim-rs"
   cargo_pkg_version = "0.11.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/strum/v0_27/BUILD.gn b/third_party/rust/strum/v0_27/BUILD.gn
index 1170459..cc043607 100644
--- a/third_party/rust/strum/v0_27/BUILD.gn
+++ b/third_party/rust/strum/v0_27/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_authors = "Peter Glotfelty <peter.glotfelty@microsoft.com>"
   cargo_pkg_name = "strum"
   cargo_pkg_description = "Helpful macros for working with enums and strings"
+  cargo_pkg_repository = "https://github.com/Peternator7/strum"
   cargo_pkg_version = "0.27.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/strum_macros/v0_27/BUILD.gn b/third_party/rust/strum_macros/v0_27/BUILD.gn
index 74f7ea7..b843485b 100644
--- a/third_party/rust/strum_macros/v0_27/BUILD.gn
+++ b/third_party/rust/strum_macros/v0_27/BUILD.gn
@@ -46,6 +46,7 @@
   cargo_pkg_authors = "Peter Glotfelty <peter.glotfelty@microsoft.com>"
   cargo_pkg_name = "strum_macros"
   cargo_pkg_description = "Helpful macros for working with enums and strings"
+  cargo_pkg_repository = "https://github.com/Peternator7/strum"
   cargo_pkg_version = "0.27.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/subtle/v2/BUILD.gn b/third_party/rust/subtle/v2/BUILD.gn
index 0ea513f..083cbbb7 100644
--- a/third_party/rust/subtle/v2/BUILD.gn
+++ b/third_party/rust/subtle/v2/BUILD.gn
@@ -23,6 +23,7 @@
   cargo_pkg_authors = "Isis Lovecruft <isis@patternsinthevoid.net>, Henry de Valence <hdevalence@hdevalence.ca>"
   cargo_pkg_name = "subtle"
   cargo_pkg_description = "Pure-Rust traits and utilities for constant-time cryptographic implementations."
+  cargo_pkg_repository = "https://github.com/dalek-cryptography/subtle"
   cargo_pkg_version = "2.6.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/symphonia/v0_5/BUILD.gn b/third_party/rust/symphonia/v0_5/BUILD.gn
index dea995b..a7512d1 100644
--- a/third_party/rust/symphonia/v0_5/BUILD.gn
+++ b/third_party/rust/symphonia/v0_5/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_name = "symphonia"
   cargo_pkg_description =
       "Pure Rust media container and audio decoding library."
+  cargo_pkg_repository = "https://github.com/pdeljanov/Symphonia"
   cargo_pkg_version = "0.5.4"
 
   allow_unsafe = false
diff --git a/third_party/rust/symphonia_bundle_flac/v0_5/BUILD.gn b/third_party/rust/symphonia_bundle_flac/v0_5/BUILD.gn
index 4c56ee4..a16c889 100644
--- a/third_party/rust/symphonia_bundle_flac/v0_5/BUILD.gn
+++ b/third_party/rust/symphonia_bundle_flac/v0_5/BUILD.gn
@@ -29,6 +29,7 @@
   cargo_pkg_name = "symphonia-bundle-flac"
   cargo_pkg_description =
       "Pure Rust FLAC demuxer and decoder (a part of project Symphonia)."
+  cargo_pkg_repository = "https://github.com/pdeljanov/Symphonia"
   cargo_pkg_version = "0.5.4"
 
   allow_unsafe = false
diff --git a/third_party/rust/symphonia_core/v0_5/BUILD.gn b/third_party/rust/symphonia_core/v0_5/BUILD.gn
index 6cb5f53b..aee2579 100644
--- a/third_party/rust/symphonia_core/v0_5/BUILD.gn
+++ b/third_party/rust/symphonia_core/v0_5/BUILD.gn
@@ -51,6 +51,7 @@
   cargo_pkg_name = "symphonia-core"
   cargo_pkg_description =
       "Project Symphonia shared structs, traits, and features."
+  cargo_pkg_repository = "https://github.com/pdeljanov/Symphonia"
   cargo_pkg_version = "0.5.4"
 
   allow_unsafe = false
diff --git a/third_party/rust/symphonia_metadata/v0_5/BUILD.gn b/third_party/rust/symphonia_metadata/v0_5/BUILD.gn
index 535262de..4ca5548 100644
--- a/third_party/rust/symphonia_metadata/v0_5/BUILD.gn
+++ b/third_party/rust/symphonia_metadata/v0_5/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_name = "symphonia-metadata"
   cargo_pkg_description =
       "Project Symphonia multimedia tag and metadata readers."
+  cargo_pkg_repository = "https://github.com/pdeljanov/Symphonia"
   cargo_pkg_version = "0.5.4"
 
   allow_unsafe = false
diff --git a/third_party/rust/symphonia_utils_xiph/v0_5/BUILD.gn b/third_party/rust/symphonia_utils_xiph/v0_5/BUILD.gn
index 5b5471d..d75ee15 100644
--- a/third_party/rust/symphonia_utils_xiph/v0_5/BUILD.gn
+++ b/third_party/rust/symphonia_utils_xiph/v0_5/BUILD.gn
@@ -27,6 +27,7 @@
   cargo_pkg_name = "symphonia-utils-xiph"
   cargo_pkg_description =
       "Project Symphonia utilities for Xiph codecs and formats."
+  cargo_pkg_repository = "https://github.com/pdeljanov/Symphonia"
   cargo_pkg_version = "0.5.4"
 
   allow_unsafe = false
diff --git a/third_party/rust/syn/v2/BUILD.gn b/third_party/rust/syn/v2/BUILD.gn
index fce4683..7ca4c55 100644
--- a/third_party/rust/syn/v2/BUILD.gn
+++ b/third_party/rust/syn/v2/BUILD.gn
@@ -77,6 +77,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "syn"
   cargo_pkg_description = "Parser for Rust source code"
+  cargo_pkg_repository = "https://github.com/dtolnay/syn"
   cargo_pkg_version = "2.0.104"
 
   allow_unsafe = true
diff --git a/third_party/rust/synstructure/v0_13/BUILD.gn b/third_party/rust/synstructure/v0_13/BUILD.gn
index 4c15b9d..0f1de7b 100644
--- a/third_party/rust/synstructure/v0_13/BUILD.gn
+++ b/third_party/rust/synstructure/v0_13/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "Nika Layzell <nika@thelayzells.com>"
   cargo_pkg_name = "synstructure"
   cargo_pkg_description = "Helper methods and macros for custom derives"
+  cargo_pkg_repository = "https://github.com/mystor/synstructure"
   cargo_pkg_version = "0.13.2"
 
   allow_unsafe = false
diff --git a/third_party/rust/temporal_capi/v0_0_11/BUILD.gn b/third_party/rust/temporal_capi/v0_0_11/BUILD.gn
index 6070e8b..49d3aa2 100644
--- a/third_party/rust/temporal_capi/v0_0_11/BUILD.gn
+++ b/third_party/rust/temporal_capi/v0_0_11/BUILD.gn
@@ -36,6 +36,7 @@
   cargo_pkg_authors = "boa-dev"
   cargo_pkg_name = "temporal_capi"
   cargo_pkg_description = "C interface to temporal_rs"
+  cargo_pkg_repository = "https://github.com/boa-dev/temporal"
   cargo_pkg_version = "0.0.11"
 
   allow_unsafe = false
diff --git a/third_party/rust/temporal_rs/v0_0_11/BUILD.gn b/third_party/rust/temporal_rs/v0_0_11/BUILD.gn
index e62a9799..f368010 100644
--- a/third_party/rust/temporal_rs/v0_0_11/BUILD.gn
+++ b/third_party/rust/temporal_rs/v0_0_11/BUILD.gn
@@ -67,6 +67,7 @@
   cargo_pkg_authors = "boa-dev"
   cargo_pkg_name = "temporal_rs"
   cargo_pkg_description = "Temporal in Rust is an implementation of the TC39 Temporal Builtin Proposal in Rust."
+  cargo_pkg_repository = "https://github.com/boa-dev/temporal"
   cargo_pkg_version = "0.0.11"
 
   allow_unsafe = true
diff --git a/third_party/rust/termcolor/v1/BUILD.gn b/third_party/rust/termcolor/v1/BUILD.gn
index d57e340..4c5af63 100644
--- a/third_party/rust/termcolor/v1/BUILD.gn
+++ b/third_party/rust/termcolor/v1/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_name = "termcolor"
   cargo_pkg_description =
       "A simple cross platform library for writing colored text to a terminal."
+  cargo_pkg_repository = "https://github.com/BurntSushi/termcolor"
   cargo_pkg_version = "1.4.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/timezone_provider/v0_0_11/BUILD.gn b/third_party/rust/timezone_provider/v0_0_11/BUILD.gn
index dbd3839..859420f 100644
--- a/third_party/rust/timezone_provider/v0_0_11/BUILD.gn
+++ b/third_party/rust/timezone_provider/v0_0_11/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_authors = "boa-dev"
   cargo_pkg_name = "timezone_provider"
   cargo_pkg_description = "Time zone data providers"
+  cargo_pkg_repository = "https://github.com/boa-dev/temporal"
   cargo_pkg_version = "0.0.11"
 
   allow_unsafe = true
diff --git a/third_party/rust/tinystr/v0_8/BUILD.gn b/third_party/rust/tinystr/v0_8/BUILD.gn
index 5831852..296fabb 100644
--- a/third_party/rust/tinystr/v0_8/BUILD.gn
+++ b/third_party/rust/tinystr/v0_8/BUILD.gn
@@ -34,6 +34,7 @@
   cargo_pkg_name = "tinystr"
   cargo_pkg_description =
       "A small ASCII-only bounded length string representation."
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.8.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/toktrie/v1/BUILD.gn b/third_party/rust/toktrie/v1/BUILD.gn
index 51a69c20..79d9af4e 100644
--- a/third_party/rust/toktrie/v1/BUILD.gn
+++ b/third_party/rust/toktrie/v1/BUILD.gn
@@ -29,6 +29,7 @@
   edition = "2021"
   cargo_pkg_name = "toktrie"
   cargo_pkg_description = "LLM Token Trie library"
+  cargo_pkg_repository = "https://github.com/guidance-ai/llguidance"
   cargo_pkg_version = "1.0.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/tzif/v0_4/BUILD.gn b/third_party/rust/tzif/v0_4/BUILD.gn
index 89fe4d05..120232a4 100644
--- a/third_party/rust/tzif/v0_4/BUILD.gn
+++ b/third_party/rust/tzif/v0_4/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "tzif"
   cargo_pkg_description = "A parser for TZif files"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.4.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/unicode_ident/v1/BUILD.gn b/third_party/rust/unicode_ident/v1/BUILD.gn
index 9dd44f5..0c362c4 100644
--- a/third_party/rust/unicode_ident/v1/BUILD.gn
+++ b/third_party/rust/unicode_ident/v1/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "unicode-ident"
   cargo_pkg_description = "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31"
+  cargo_pkg_repository = "https://github.com/dtolnay/unicode-ident"
   cargo_pkg_version = "1.0.18"
 
   allow_unsafe = true
diff --git a/third_party/rust/unicode_width/v0_2/BUILD.gn b/third_party/rust/unicode_width/v0_2/BUILD.gn
index a14acb36..7ce696d3 100644
--- a/third_party/rust/unicode_width/v0_2/BUILD.gn
+++ b/third_party/rust/unicode_width/v0_2/BUILD.gn
@@ -25,6 +25,7 @@
       "kwantam <kwantam@gmail.com>, Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "unicode-width"
   cargo_pkg_description = "Determine displayed width of `char` and `str` types according to Unicode Standard Annex #11 rules."
+  cargo_pkg_repository = "https://github.com/unicode-rs/unicode-width"
   cargo_pkg_version = "0.2.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/winapi_util/v0_1/BUILD.gn b/third_party/rust/winapi_util/v0_1/BUILD.gn
index 048a35a..2bef723 100644
--- a/third_party/rust/winapi_util/v0_1/BUILD.gn
+++ b/third_party/rust/winapi_util/v0_1/BUILD.gn
@@ -30,6 +30,7 @@
   cargo_pkg_name = "winapi-util"
   cargo_pkg_description =
       "A dumping ground for high level safe wrappers over windows-sys."
+  cargo_pkg_repository = "https://github.com/BurntSushi/winapi-util"
   cargo_pkg_version = "0.1.9"
 
   allow_unsafe = true
diff --git a/third_party/rust/windows_aarch64_msvc/v0_52/BUILD.gn b/third_party/rust/windows_aarch64_msvc/v0_52/BUILD.gn
index aa8b4e8..f83ba0d2 100644
--- a/third_party/rust/windows_aarch64_msvc/v0_52/BUILD.gn
+++ b/third_party/rust/windows_aarch64_msvc/v0_52/BUILD.gn
@@ -22,6 +22,7 @@
   cargo_pkg_authors = "Microsoft"
   cargo_pkg_name = "windows_aarch64_msvc"
   cargo_pkg_description = "Import lib for Windows"
+  cargo_pkg_repository = "https://github.com/microsoft/windows-rs"
   cargo_pkg_version = "0.52.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/windows_i686_msvc/v0_52/BUILD.gn b/third_party/rust/windows_i686_msvc/v0_52/BUILD.gn
index 66364fa..22f7c01 100644
--- a/third_party/rust/windows_i686_msvc/v0_52/BUILD.gn
+++ b/third_party/rust/windows_i686_msvc/v0_52/BUILD.gn
@@ -22,6 +22,7 @@
   cargo_pkg_authors = "Microsoft"
   cargo_pkg_name = "windows_i686_msvc"
   cargo_pkg_description = "Import lib for Windows"
+  cargo_pkg_repository = "https://github.com/microsoft/windows-rs"
   cargo_pkg_version = "0.52.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/windows_sys/v0_52/BUILD.gn b/third_party/rust/windows_sys/v0_52/BUILD.gn
index 551ab88..bbcc16b 100644
--- a/third_party/rust/windows_sys/v0_52/BUILD.gn
+++ b/third_party/rust/windows_sys/v0_52/BUILD.gn
@@ -258,6 +258,7 @@
   cargo_pkg_authors = "Microsoft"
   cargo_pkg_name = "windows-sys"
   cargo_pkg_description = "Rust for Windows"
+  cargo_pkg_repository = "https://github.com/microsoft/windows-rs"
   cargo_pkg_version = "0.52.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/windows_targets/v0_52/BUILD.gn b/third_party/rust/windows_targets/v0_52/BUILD.gn
index 2820e09..7e00563 100644
--- a/third_party/rust/windows_targets/v0_52/BUILD.gn
+++ b/third_party/rust/windows_targets/v0_52/BUILD.gn
@@ -22,6 +22,7 @@
   cargo_pkg_authors = "Microsoft"
   cargo_pkg_name = "windows-targets"
   cargo_pkg_description = "Import libs for Windows"
+  cargo_pkg_repository = "https://github.com/microsoft/windows-rs"
   cargo_pkg_version = "0.52.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/windows_x86_64_msvc/v0_52/BUILD.gn b/third_party/rust/windows_x86_64_msvc/v0_52/BUILD.gn
index 18c29fe2..0cc14626 100644
--- a/third_party/rust/windows_x86_64_msvc/v0_52/BUILD.gn
+++ b/third_party/rust/windows_x86_64_msvc/v0_52/BUILD.gn
@@ -22,6 +22,7 @@
   cargo_pkg_authors = "Microsoft"
   cargo_pkg_name = "windows_x86_64_msvc"
   cargo_pkg_description = "Import lib for Windows"
+  cargo_pkg_repository = "https://github.com/microsoft/windows-rs"
   cargo_pkg_version = "0.52.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/writeable/v0_6/BUILD.gn b/third_party/rust/writeable/v0_6/BUILD.gn
index 918eac9..aeb52d1 100644
--- a/third_party/rust/writeable/v0_6/BUILD.gn
+++ b/third_party/rust/writeable/v0_6/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "writeable"
   cargo_pkg_description = "A more efficient alternative to fmt::Display"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.6.1"
 
   allow_unsafe = true
diff --git a/third_party/rust/yoke/v0_8/BUILD.gn b/third_party/rust/yoke/v0_8/BUILD.gn
index d4da33d..519ef8e 100644
--- a/third_party/rust/yoke/v0_8/BUILD.gn
+++ b/third_party/rust/yoke/v0_8/BUILD.gn
@@ -32,6 +32,7 @@
   cargo_pkg_authors = "Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "yoke"
   cargo_pkg_description = "Abstraction allowing borrowed data to be carried along with the backing data it borrows from"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.8.0"
 
   allow_unsafe = true
diff --git a/third_party/rust/yoke_derive/v0_8/BUILD.gn b/third_party/rust/yoke_derive/v0_8/BUILD.gn
index 2d472ed..512139e 100644
--- a/third_party/rust/yoke_derive/v0_8/BUILD.gn
+++ b/third_party/rust/yoke_derive/v0_8/BUILD.gn
@@ -25,6 +25,7 @@
   cargo_pkg_authors = "Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "yoke-derive"
   cargo_pkg_description = "Custom derive for the yoke crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.8.0"
 
   allow_unsafe = false
diff --git a/third_party/rust/zerofrom/v0_1/BUILD.gn b/third_party/rust/zerofrom/v0_1/BUILD.gn
index 5aecdc1..9bb83c0 100644
--- a/third_party/rust/zerofrom/v0_1/BUILD.gn
+++ b/third_party/rust/zerofrom/v0_1/BUILD.gn
@@ -26,6 +26,7 @@
   cargo_pkg_authors = "Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "zerofrom"
   cargo_pkg_description = "ZeroFrom trait for constructing"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.1.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/zerofrom_derive/v0_1/BUILD.gn b/third_party/rust/zerofrom_derive/v0_1/BUILD.gn
index 69c733e..78d38cc7 100644
--- a/third_party/rust/zerofrom_derive/v0_1/BUILD.gn
+++ b/third_party/rust/zerofrom_derive/v0_1/BUILD.gn
@@ -24,6 +24,7 @@
   cargo_pkg_authors = "Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "zerofrom-derive"
   cargo_pkg_description = "Custom derive for the zerofrom crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.1.6"
 
   allow_unsafe = false
diff --git a/third_party/rust/zerotrie/v0_2/BUILD.gn b/third_party/rust/zerotrie/v0_2/BUILD.gn
index 7676b7ff..445e4df 100644
--- a/third_party/rust/zerotrie/v0_2/BUILD.gn
+++ b/third_party/rust/zerotrie/v0_2/BUILD.gn
@@ -46,6 +46,7 @@
   cargo_pkg_name = "zerotrie"
   cargo_pkg_description =
       "A data structure that efficiently maps strings to integers"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.2.2"
 
   allow_unsafe = true
diff --git a/third_party/rust/zerovec/v0_11/BUILD.gn b/third_party/rust/zerovec/v0_11/BUILD.gn
index 1a3b74f..1fc78f2 100644
--- a/third_party/rust/zerovec/v0_11/BUILD.gn
+++ b/third_party/rust/zerovec/v0_11/BUILD.gn
@@ -72,6 +72,7 @@
   cargo_pkg_authors = "The ICU4X Project Developers"
   cargo_pkg_name = "zerovec"
   cargo_pkg_description = "Zero-copy vector backed by a byte array"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.11.2"
 
   allow_unsafe = true
diff --git a/third_party/rust/zerovec_derive/v0_11/BUILD.gn b/third_party/rust/zerovec_derive/v0_11/BUILD.gn
index a1d1452c..31b9750 100644
--- a/third_party/rust/zerovec_derive/v0_11/BUILD.gn
+++ b/third_party/rust/zerovec_derive/v0_11/BUILD.gn
@@ -28,6 +28,7 @@
   cargo_pkg_authors = "Manish Goregaokar <manishsmail@gmail.com>"
   cargo_pkg_name = "zerovec-derive"
   cargo_pkg_description = "Custom derive for the zerovec crate"
+  cargo_pkg_repository = "https://github.com/unicode-org/icu4x"
   cargo_pkg_version = "0.11.1"
 
   allow_unsafe = false
diff --git a/third_party/rust/zip/v4/BUILD.gn b/third_party/rust/zip/v4/BUILD.gn
index 78fc53d..b72af534 100644
--- a/third_party/rust/zip/v4/BUILD.gn
+++ b/third_party/rust/zip/v4/BUILD.gn
@@ -44,6 +44,7 @@
   cargo_pkg_name = "zip"
   cargo_pkg_description =
       "Library to support the reading and writing of zip files."
+  cargo_pkg_repository = "https://github.com/zip-rs/zip2.git"
   cargo_pkg_version = "4.3.0"
 
   allow_unsafe = true
diff --git a/third_party/skia b/third_party/skia
index 626ab31..43a4c13 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 626ab317e2679f0e8d63d78e8a8654e22f954227
+Subproject commit 43a4c13a8c57ecea1dc9842f8cfda766633ba40d
diff --git a/third_party/swiftshader b/third_party/swiftshader
index b347398..a84d180 160000
--- a/third_party/swiftshader
+++ b/third_party/swiftshader
@@ -1 +1 @@
-Subproject commit b347398f5e864dc2853c15da12efcd33c5412e1b
+Subproject commit a84d1801cf7b144da1cd3cca423ef36907c01771
diff --git a/tools/crates/gnrt/lib/deps.rs b/tools/crates/gnrt/lib/deps.rs
index 7f90722..b51157e 100644
--- a/tools/crates/gnrt/lib/deps.rs
+++ b/tools/crates/gnrt/lib/deps.rs
@@ -38,6 +38,7 @@
     pub description: Option<String>,
     pub authors: Vec<String>,
     pub edition: String,
+    pub repository: Option<String>,
     /// This package's dependencies. Each element cross-references another
     /// `Package` by name and version.
     pub dependencies: Vec<DepOfDep>,
@@ -314,6 +315,7 @@
                 description: package.description().map(|s| s.to_string()),
                 authors: package.authors().to_vec(),
                 edition: package.edition().to_string(),
+                repository: package.repository().map(|s| s.to_string()),
                 dependencies,
                 build_dependencies,
                 dependency_kinds,
diff --git a/tools/crates/gnrt/lib/gn.rs b/tools/crates/gnrt/lib/gn.rs
index eaed0ba..996b75e 100644
--- a/tools/crates/gnrt/lib/gn.rs
+++ b/tools/crates/gnrt/lib/gn.rs
@@ -75,6 +75,7 @@
     pub cargo_pkg_authors: Option<String>,
     pub cargo_pkg_name: String,
     pub cargo_pkg_description: Option<String>,
+    pub cargo_pkg_repository: Option<String>,
     pub deps: Vec<DepGroup>,
     pub build_deps: Vec<DepGroup>,
     pub aliased_deps: Vec<(String, PackageId)>,
@@ -192,6 +193,7 @@
         cargo_pkg_authors,
         cargo_pkg_name: dep.package_name.to_string(),
         cargo_pkg_description: dep.description.as_ref().map(|s| s.trim_end().to_string()),
+        cargo_pkg_repository: dep.repository.as_ref().map(|s| s.trim_end().to_string()),
 
         cond,
         extra_kv,
diff --git a/tools/crates/gnrt/lib/readme.rs b/tools/crates/gnrt/lib/readme.rs
index 353bbb12..793a590 100644
--- a/tools/crates/gnrt/lib/readme.rs
+++ b/tools/crates/gnrt/lib/readme.rs
@@ -234,6 +234,12 @@
 
     /// https://spdx.org/licenses/Unicode-3.0.html
     Unicode3,
+
+    /// https://spdx.org/licenses/NCSA.html
+    NCSA,
+
+    /// https://spdx.org/licenses/BSL-1.0.html
+    BSL,
 }
 
 impl Display for LicenseKind {
@@ -247,8 +253,10 @@
             LicenseKind::MIT => write!(f, "MIT"),
             LicenseKind::MPL2 => write!(f, "MPL-2.0"),
             LicenseKind::ISC => write!(f, "ISC"),
+            LicenseKind::NCSA => write!(f, "NCSA"),
             LicenseKind::Zlib => write!(f, "Zlib"),
             LicenseKind::Unicode3 => write!(f, "Unicode-3.0"),
+            LicenseKind::BSL => write!(f, "BSL-1.0"),
         }
     }
 }
@@ -273,6 +281,7 @@
             ("Apache-2.0/MIT", vec![LicenseKind::Apache2]),
             ("(Apache-2.0 OR MIT) AND BSD-3-Clause", vec![LicenseKind::Apache2, LicenseKind::BSD3]),
             ("MIT OR Apache-2.0 OR Zlib", vec![LicenseKind::Apache2]),
+            ("(MIT OR Apache-2.0) AND NCSA", vec![LicenseKind::Apache2, LicenseKind::NCSA]),
             ("MIT", vec![LicenseKind::MIT]),
             ("MPL-2.0", vec![LicenseKind::MPL2]),
             ("Unlicense OR MIT", vec![LicenseKind::MIT]),
@@ -290,8 +299,12 @@
             ("MIT AND (MIT OR Apache-2.0)", vec![LicenseKind::Apache2]),
             ("Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", vec![LicenseKind::Apache2]),
             ("BSD-2-Clause OR Apache-2.0 OR MIT", vec![LicenseKind::Apache2]),
+            ("BSD-2-Clause OR Apache-2.0 OR MIT", vec![LicenseKind::Apache2]),
+            ("BSD-2-Clause OR MIT OR Apache-2.0", vec![LicenseKind::Apache2]),
+            ("BSD-3-Clause OR MIT OR Apache-2.0", vec![LicenseKind::Apache2]),
             ("Unicode-3.0", vec![LicenseKind::Unicode3]),
             ("Zlib", vec![LicenseKind::Zlib]),
+            ("BSL-1.0", vec![LicenseKind::BSL]),
         ])
     });
 
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index ede0b75..fc2b0e45 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -524,6 +524,7 @@
     ]
     cmd.extend(targets)
     cmd.extend(['--sts-config-file', self.args.sts_config_file])
+    cmd.extend(['--test-selection-phase', 'TRIGGER'])
 
     ret, _, _ = self.Run(cmd, force_verbose=True, capture_output=True)
     if ret:
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 3dc7bdf43..28a1ca7 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -13402,6 +13402,12 @@
   </description>
 </action>
 
+<action name="Hub.BackButtonPressed">
+  <owner>ckitagawa@chromium.org</owner>
+  <owner>skym@chromium.org</owner>
+  <description>The user pressed the back button to close the Hub.</description>
+</action>
+
 <action name="HubSearch.KeyboardEnterPressed">
   <owner>wylieb@google.com</owner>
   <owner>bjfong@google.com</owner>
@@ -15094,7 +15100,7 @@
 
 <action name="IOS.DefaultBrowserFullscreenPromo.Cancel">
   <owner>gayane@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed the default browser fullscreen promo by pressing on
     secondary button. iOS only.
@@ -15147,7 +15153,7 @@
 
 <action name="IOS.DefaultBrowserPromo.NonModal.Accepted">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user accepted a non modal promo. This will either take them to the
     settings instructions for default browser ot directly into settings. To
@@ -15158,7 +15164,7 @@
 
 <action name="IOS.DefaultBrowserPromo.NonModal.Appear">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user triggered a non modal default promo, and it appeared. iOS only.
   </description>
@@ -15166,7 +15172,7 @@
 
 <action name="IOS.DefaultBrowserPromo.NonModal.Dismiss">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed explicitly a non modal promo. iOS only.
   </description>
@@ -15174,7 +15180,7 @@
 
 <action name="IOS.DefaultBrowserPromo.NonModal.Timeout">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     A non modal promo timed out and was dismissed. iOS only.
   </description>
@@ -15182,7 +15188,7 @@
 
 <action name="IOS.DefaultBrowserPromo.SetUpList.Accepted">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user accepted a Set Up List default browser promo modal, and was taken
     to the Settings app. iOS only.
@@ -15191,7 +15197,7 @@
 
 <action name="IOS.DefaultBrowserPromo.SetUpList.Appear">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user triggered the SetUpList default browser promo and it appeared, iOS
     only.
@@ -15200,7 +15206,7 @@
 
 <action name="IOS.DefaultBrowserPromo.SetUpList.Dismiss">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed a Set Up List default browser promo modal. iOS only.
   </description>
@@ -15208,7 +15214,7 @@
 
 <action name="IOS.DefaultBrowserPromo.TailoredFullscreen.Accepted">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user accepted a tailored browser fullscreen promo modal, and was taken
     to the Settings app. iOS only.
@@ -15217,13 +15223,13 @@
 
 <action name="IOS.DefaultBrowserPromo.TailoredFullscreen.Appear">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>A tailored fullscren promo appeared. iOS only.</description>
 </action>
 
 <action name="IOS.DefaultBrowserPromo.TailoredFullscreen.Cancel">
   <owner>gayane@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed a tailored browser fullscreen promo modal using secondary
     action button. iOS only.
@@ -15232,7 +15238,7 @@
 
 <action name="IOS.DefaultBrowserPromo.TailoredFullscreen.Dismiss">
   <owner>rkgibson@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed a tailored browser fullscreen promo modal by swiping
     down. iOS only.
@@ -15241,7 +15247,7 @@
 
 <action name="IOS.DefaultBrowserPromo.TailoredFullscreen.MoreInfoTapped">
   <owner>gayane@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user tapped on the more information icon on the tailored browser
     fullscreen promo modal. iOS only.
@@ -15251,7 +15257,7 @@
 <action name="IOS.DefaultBrowserVideoPromo.Appear">
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user is presented with the default browser video promo. iOS only.
   </description>
@@ -15260,7 +15266,7 @@
 <action name="IOS.DefaultBrowserVideoPromo.Fullscreen.Dismiss">
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed the full screen default browser video promo. iOS only.
   </description>
@@ -15269,7 +15275,7 @@
 <action name="IOS.DefaultBrowserVideoPromo.Fullscreen.Impression">
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user is presented with the fullscreen screen arm of the default browser
     video promo. iOS only.
@@ -15279,7 +15285,7 @@
 <action name="IOS.DefaultBrowserVideoPromo.Fullscreen.OpenSettingsTapped">
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user accepted the full screen default browser video promo, and was taken
     to the Settings app. iOS only.
@@ -15289,7 +15295,7 @@
 <action name="IOS.DefaultBrowserVideoPromo.Fullscreen.RemindMeLater">
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user asked to be reminded later on the full screen default browser video
     promo. iOS only.
@@ -15300,7 +15306,7 @@
   <obsolete>This UI was removed in M123.</obsolete>
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user dismissed the half screen default browser video promo. iOS only.
   </description>
@@ -15310,7 +15316,7 @@
   <obsolete>This UI was removed in M123.</obsolete>
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user is presented with the half screen arm of the default browser video
     promo. iOS only.
@@ -15321,7 +15327,7 @@
   <obsolete>This UI was removed in M123.</obsolete>
   <owner>cheickcisse@google.com</owner>
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     The user accepted the half screen default browser video promo, and was taken
     to the full screen default browser video promo. iOS only.
@@ -15462,7 +15468,7 @@
 
 <action name="IOS.HomeCustomization.MagicStackPage.ParcelTracking.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Parcel Tracking cell is toggled from the Magic Stack page
     in the Home Customization menu.
@@ -15471,7 +15477,7 @@
 
 <action name="IOS.HomeCustomization.MagicStackPage.SafetyCheck.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Safety Check cell is toggled from the Magic Stack page in
     the Home Customization menu.
@@ -15480,7 +15486,7 @@
 
 <action name="IOS.HomeCustomization.MagicStackPage.SetUpList.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Set Up list cell is toggled from the Magic Stack page in
     the Home Customization menu.
@@ -15512,7 +15518,7 @@
 
 <action name="IOS.HomeCustomization.MagicStackPage.TabResumption.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Tab Resumption cell is toggled from the Magic Stack page
     in the Home Customization menu.
@@ -15522,7 +15528,7 @@
 <action name="IOS.HomeCustomization.MagicStackPage.Tips.Toggled">
   <owner>bwwilliams@google.com</owner>
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Tips cell is toggled from the Magic Stack page in the Home
     Customization menu.
@@ -15531,7 +15537,7 @@
 
 <action name="IOS.HomeCustomization.MainPage.Feed.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Feed cell is toggled from the Home Customization menu.
   </description>
@@ -15539,7 +15545,7 @@
 
 <action name="IOS.HomeCustomization.MainPage.MagicStack.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Magic Stack cell is toggled from the Home Customization
     menu.
@@ -15548,7 +15554,7 @@
 
 <action name="IOS.HomeCustomization.MainPage.MostVisited.Toggled">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Reported when the Most Visited cell is toggled from the Home Customization
     menu.
@@ -15761,7 +15767,7 @@
 
 <action name="IOS.Notifications.SendTab.Interaction">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when a user taps on a Send Tab push notification.
   </description>
@@ -15935,7 +15941,7 @@
 
 <action name="IOS.PostRestoreDefaultBrowser.Displayed">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when the Post Restore Default Browser Promo is displayed. iOS only.
   </description>
@@ -16069,13 +16075,13 @@
 
 <action name="IOSBookmarksAddedInBulk">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>User added bookmarks in bulk.</description>
 </action>
 
 <action name="IOSBookmarksAddedInBulkSnackbarViewButtonClicked">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when a user clicks the &quot;view&quot; button in the snackbar
     generated from bulk adding bookmarks. iOS-only.
@@ -16336,13 +16342,13 @@
 
 <action name="IOSLaunchedByAddBookmarkToChromeIntent">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>User added bookmarks to Chrome via Apple Shortcuts.</description>
 </action>
 
 <action name="IOSLaunchedByAddReadingListItemToChromeIntent">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>User added a reading list item via Apple Shortcuts.</description>
 </action>
 
@@ -16470,7 +16476,7 @@
 
 <action name="IOSReadingListItemsAddedInBulk">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when a user bulk adds reading list items (Siri Shortcut). iOS-only.
   </description>
@@ -16478,7 +16484,7 @@
 
 <action name="IOSReadingListSnackbarViewButtonClicked">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when a user clicks the &quot;view&quot; button in the snackbar
     generated from bulk adding reading list items. iOS-only.
@@ -22534,7 +22540,7 @@
 
 <action name="Mobile.Omnibox.iOS.PastedValidURL">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     User tapped the 'paste' iOS/iPadOS button into the Omnibox and the resulting
     text in the Omnibox is a valid URL. iOS and iPadOS only.
@@ -24863,6 +24869,14 @@
   <description>User pressed 'New incognito tab' in the app menu.</description>
 </action>
 
+<action name="MobileMenuNewIncognitoWindow">
+  <owner>shuyng@google.com</owner>
+  <owner>clank-large-form-factors@google.com</owner>
+  <description>
+    User pressed 'New incognito window' in the app menu.
+  </description>
+</action>
+
 <action name="MobileMenuNewTab">
   <owner>aurimas@chromium.org</owner>
   <description>User pressed 'New tab' in the app menu.</description>
@@ -25378,7 +25392,7 @@
 
 <action name="MobileNTPCustomizationNewBadgeShown">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when the new feature badge is shown on the Home Customization
     menu's entrypoint.
@@ -25387,7 +25401,7 @@
 
 <action name="MobileNTPCustomizationNewBadgeTapped">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when the Home Customization menu's entrypoint is tapped while the
     new feature badge is visible.
@@ -40328,7 +40342,7 @@
 
 <action name="Signin_Impression_FromPostDeviceRestoreSigninPromo">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when showing sign in after the post restore signin promo.
   </description>
@@ -40399,7 +40413,7 @@
 
 <action name="Signin_Impression_FromSetUpList">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded when showing sign in that originates from the Set Up List on the
     NTP. iOS only.
@@ -41298,7 +41312,7 @@
 
 <action name="Signin_Signin_FromPostDeviceRestoreSigninPromo">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded on sign in start from access point
     signin_metrics::AccessPoint::kPostDeviceRestoreSigninPromo.
@@ -41386,7 +41400,7 @@
 
 <action name="Signin_Signin_FromSetUpList">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <description>
     Recorded on sign in start from access point
     signin_metrics::AccessPoint::kSetUpList. iOS only.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5c1f4530..5a17eae 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2605,6 +2605,7 @@
   <int value="137" label="Translator API languages initialized by site"/>
   <int value="138" label="Suspicious notification ids"/>
   <int value="139" label="Geolocation with options"/>
+  <int value="140" label="Device Attributes"/>
 </enum>
 
 <!-- LINT.ThenChange(//components/content_settings/core/browser/content_settings_uma_util.cc:kHistogramValue) -->
@@ -12855,6 +12856,7 @@
   <int value="-454362199" label="HelpAppV2:disabled"/>
   <int value="-454359275" label="kQuickAnswersMaterialNextUI:disabled"/>
   <int value="-454246685" label="AndroidAppIntegrationWithFavicon:disabled"/>
+  <int value="-453506590" label="MediaLinkHelpers:disabled"/>
   <int value="-452734575" label="ArcExtendInputAnrTimeout:enabled"/>
   <int value="-451898735" label="private-aggregation-developer-mode"/>
   <int value="-450976085"
@@ -15721,6 +15723,7 @@
   <int value="613629912" label="LookalikeUrlNavigationSuggestions:enabled"/>
   <int value="614174812" label="GlobalMediaControlsOverlayControls:disabled"/>
   <int value="615008173" label="UserAgentOverrideExperiment:enabled"/>
+  <int value="615382282" label="GlicFreWarming:disabled"/>
   <int value="615437216"
       label="CrOSLateBootChromeboxUsbPassthroughRestrictions:enabled"/>
   <int value="615733361" label="DiscardOccludedBitmaps:disabled"/>
@@ -17121,6 +17124,7 @@
   <int value="1122217615" label="PasswordGenerationBottomSheet:enabled"/>
   <int value="1122327201"
       label="MediaFoundationCameraUsageMonitoring:disabled"/>
+  <int value="1122442180" label="MediaLinkHelpers:enabled"/>
   <int value="1122820469" label="ArcImageCopyPasteCompat:enabled"/>
   <int value="1122825280" label="FontationsFontBackend:enabled"/>
   <int value="1123140537" label="tab-link-drag-drop:disabled"/>
@@ -18090,6 +18094,7 @@
   <int value="1467322206" label="AssistAutoCorrect:enabled"/>
   <int value="1467494310" label="JavaScriptExperimentalSharedMemory:enabled"/>
   <int value="1467583815" label="AVIF:disabled"/>
+  <int value="1467956567" label="GlicWarming:disabled"/>
   <int value="1469407485" label="disable-accelerated-2d-canvas"/>
   <int value="1470134259" label="NtpTabResumptionModule:disabled"/>
   <int value="1471169381" label="kWebSQLAccess:enabled"/>
@@ -18572,6 +18577,7 @@
   <int value="1646097198" label="TranslationAPI:disabled"/>
   <int value="1646498561" label="OfflineBookmarks:disabled"/>
   <int value="1646500529" label="BacklightOcr:enabled"/>
+  <int value="1647226742" label="GlicWarming:enabled"/>
   <int value="1649121568" label="DynamicTcmallocTuning:disabled"/>
   <int value="1649168777" label="EdgeToEdgeSafeAreaConstraint:disabled"/>
   <int value="1649624189" label="PhoneHubFeatureSetupErrorHandling:disabled"/>
@@ -19678,6 +19684,7 @@
   <int value="2035351945" label="lacros-selection-policy-ignore"/>
   <int value="2035415906" label="Win11StyleMenus:enabled"/>
   <int value="2035524582" label="WebViewRecordAppDataDirectorySize:disabled"/>
+  <int value="2035867849" label="GlicFreWarming:enabled"/>
   <int value="2036196106" label="WebAuthenticationPasskeyUpgrade:enabled"/>
   <int value="2036398832" label="AiSettingsPageRefresh:disabled"/>
   <int value="2037407406" label="CrostiniQtImeSupport:disabled"/>
@@ -21730,32 +21737,6 @@
   <int value="3" label="After First Paint"/>
 </enum>
 
-<enum name="PasswordAccessLossWarningExportStep">
-  <int value="0" label="Password serialization failed"/>
-  <int value="1" label="Export with deletion was rejected"/>
-  <int value="2" label="No screen lock set up"/>
-  <int value="3" label="Saving exported passwords failed"/>
-  <int value="4" label="Export was aborted because authenticaiton expired"/>
-  <int value="5" label="Passwords were exported"/>
-  <int value="6" label="Password import rejected"/>
-  <int value="7" label="The GMS Core UI for password import was opened"/>
-</enum>
-
-<enum name="PasswordAccessLossWarningTriggers">
-  <int value="0" label="Chrome started up"/>
-  <int value="1" label="A password was saved or updated"/>
-  <int value="2" label="A credential was filled via touch to fill sheet"/>
-  <int value="3" label="A credential was filled via keyboard accessory sheet"/>
-  <int value="4" label="A credential was filled via keyboard accessory bar"/>
-  <int value="5" label="A credential was filled via all passwords sheet"/>
-</enum>
-
-<enum name="PasswordAccessLossWarningUserActions">
-  <int value="0" label="The main action was taken"/>
-  <int value="1" label="The help center link was opened"/>
-  <int value="2" label="The sheet was dismissed"/>
-</enum>
-
 <enum name="PasswordBubbleDismissalReason">
   <int value="0" label="Unknown"/>
   <int value="1" label="Accepted"/>
diff --git a/tools/metrics/histograms/metadata/accessibility/enums.xml b/tools/metrics/histograms/metadata/accessibility/enums.xml
index 63d2838..a14a8b44 100644
--- a/tools/metrics/histograms/metadata/accessibility/enums.xml
+++ b/tools/metrics/histograms/metadata/accessibility/enums.xml
@@ -2135,6 +2135,18 @@
 
 <!-- LINT.ThenChange(//chrome/renderer/accessibility/read_anything/read_anything_app_model.cc:ReadAnythingHeuristics) -->
 
+<!-- LINT.IfChange(ReadAnythingHighlightGranularity) -->
+
+<enum name="ReadAnythingHighlightGranularity">
+  <int value="0" label="Highlight auto"/>
+  <int value="1" label="Highlight off"/>
+  <int value="2" label="Highlight word"/>
+  <int value="3" label="Highlight phrase"/>
+  <int value="4" label="Hihglight sentence"/>
+</enum>
+
+<!-- LINT.ThenChange(//chrome/browser/resources/side_panel/read_anything/metrics_browser_proxy.ts:ReadAloudHighlightGranularity) -->
+
 <!-- LINT.IfChange(ReadAnythingHighlightState) -->
 
 <enum name="ReadAnythingHighlightState">
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index 6676507..97be9f2 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -3077,13 +3077,16 @@
 </histogram>
 
 <histogram name="Accessibility.ReadAnything.ReadAloud.HighlightGranularity"
-    enum="ReadAnythingHighlightState" expires_after="2026-06-01">
+    enum="ReadAnythingHighlightGranularity" expires_after="2026-06-01">
   <owner>ajitnarayanan@google.com</owner>
-  <owner>xiangxiao@google.com</owner>
+  <owner>kristislee@google.com</owner>
+  <owner>ammedina@google.com</owner>
   <owner>komo-eng@google.com</owner>
   <summary>
     Records the user-chosen highlight granularity for reading aloud in the Read
-    Anything panel.
+    Anything panel. There was an error in the enum before 2025-07-22. This
+    shouldn't affect the release of the feature to stable but use caution when
+    interpreting results before that date.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/account_manager/histograms.xml b/tools/metrics/histograms/metadata/account_manager/histograms.xml
index 4a25fd7..0af598f 100644
--- a/tools/metrics/histograms/metadata/account_manager/histograms.xml
+++ b/tools/metrics/histograms/metadata/account_manager/histograms.xml
@@ -51,7 +51,8 @@
 
 <histogram name="AccountManager.EduCoexistence.FetchAccessTokenResult"
     enum="GoogleServiceAuthError" expires_after="2025-10-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The result of fetching an access token for the child with `accounts.reauth`
@@ -62,7 +63,8 @@
 
 <histogram name="AccountManager.EduCoexistenceV2.InSessionFlowResult"
     enum="EduCoexistenceFlowV2Result" expires_after="2025-10-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the last completed step in the EDU account addition flow. Allows to
@@ -72,7 +74,8 @@
 
 <histogram name="AccountManager.EduCoexistenceV2.OnboardingFlowResult"
     enum="EduCoexistenceFlowV2Result" expires_after="2025-10-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the last completed step in the EDU account addition flow. Allows to
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 026c7852..1c00094 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1807,7 +1807,7 @@
 
 <histogram
     name="Ash.CaptureModeController.AudioRecordingMode.{TabletOrClamshellMode}"
-    enum="AudioRecordingMode" expires_after="2025-10-08">
+    enum="AudioRecordingMode" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1819,7 +1819,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.BarButtons.{TabletOrClamshellMode}"
-    enum="CaptureModeBarButtonType" expires_after="2025-10-08">
+    enum="CaptureModeBarButtonType" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1832,7 +1832,7 @@
 
 <histogram
     name="Ash.CaptureModeController.CameraDisconnectionsDuringRecordings.{TabletOrClamshellMode}"
-    units="camera disconnections" expires_after="2025-10-08">
+    units="camera disconnections" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1844,7 +1844,7 @@
 
 <histogram
     name="Ash.CaptureModeController.CameraReconnectDuration.{TabletOrClamshellMode}"
-    units="seconds" expires_after="2025-10-08">
+    units="seconds" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1856,7 +1856,7 @@
 
 <histogram
     name="Ash.CaptureModeController.CaptureConfiguration.{TabletOrClamshellMode}"
-    enum="CaptureModeConfiguration" expires_after="2025-12-07">
+    enum="CaptureModeConfiguration" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1869,7 +1869,7 @@
 
 <histogram
     name="Ash.CaptureModeController.CaptureRegionAdjusted.{TabletOrClamshellMode}"
-    units="adjustments" expires_after="2025-10-08">
+    units="adjustments" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1885,7 +1885,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.ConsecutiveScreenshots"
-    units="consecutive screenshots" expires_after="2025-10-08">
+    units="consecutive screenshots" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1897,7 +1897,7 @@
 
 <histogram
     name="Ash.CaptureModeController.DemoToolsEnabledOnRecordingStart.{TabletOrClamshellMode}"
-    enum="BooleanEnabled" expires_after="2025-10-08">
+    enum="BooleanEnabled" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1909,7 +1909,7 @@
 
 <histogram
     name="Ash.CaptureModeController.EndRecordingReason.{TabletOrClamshellMode}"
-    enum="EndRecordingReason" expires_after="2025-12-07">
+    enum="EndRecordingReason" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1921,7 +1921,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.EntryPoint.{TabletOrClamshellMode}"
-    enum="CaptureModeEntryType" expires_after="2025-12-07">
+    enum="CaptureModeEntryType" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1933,7 +1933,7 @@
 
 <histogram
     name="Ash.CaptureModeController.GameDashboard.SaveLocation.{TabletOrClamshellMode}"
-    enum="CaptureModeSaveToLocation" expires_after="2025-12-07">
+    enum="CaptureModeSaveToLocation" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1946,7 +1946,7 @@
 
 <histogram
     name="Ash.CaptureModeController.GameDashboard.ScreenRecordingFileSize.{TabletOrClamshellMode}"
-    units="KB" expires_after="2025-12-07">
+    units="KB" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1959,7 +1959,7 @@
 
 <histogram
     name="Ash.CaptureModeController.GIFRecordingFileSize.{TabletOrClamshellMode}"
-    units="KB" expires_after="2025-10-08">
+    units="KB" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1972,7 +1972,7 @@
 
 <histogram
     name="Ash.CaptureModeController.GIFRecordingLength.{TabletOrClamshellMode}"
-    units="seconds" expires_after="2025-12-07">
+    units="seconds" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1985,7 +1985,7 @@
 
 <histogram
     name="Ash.CaptureModeController.GIFRecordingRegionToScreenRatio.{TabletOrClamshellMode}"
-    units="% of fullscreen area" expires_after="2025-10-08">
+    units="% of fullscreen area" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -1997,7 +1997,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.NumberOfConnectedCameras"
-    units="connected cameras" expires_after="2025-10-08">
+    units="connected cameras" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2008,7 +2008,7 @@
 
 <histogram
     name="Ash.CaptureModeController.Projector.CaptureRegionAdjusted.{TabletOrClamshellMode}"
-    units="adjustments" expires_after="2025-10-08">
+    units="adjustments" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2023,7 +2023,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.QuickAction"
-    enum="CaptureQuickAction" expires_after="2025-10-08">
+    enum="CaptureQuickAction" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
@@ -2035,7 +2035,7 @@
 
 <histogram
     name="Ash.CaptureModeController.RecordingCameraPositionOnStart.{TabletOrClamshellMode}"
-    enum="CameraPreviewSnapPosition" expires_after="2025-10-08">
+    enum="CameraPreviewSnapPosition" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2047,7 +2047,7 @@
 
 <histogram
     name="Ash.CaptureModeController.RecordingCameraSizeOnStart.{TabletOrClamshellMode}"
-    enum="CaptureModeCameraSize" expires_after="2025-10-08">
+    enum="CaptureModeCameraSize" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2059,7 +2059,7 @@
 
 <histogram
     name="Ash.CaptureModeController.RecordingStartsWithCamera.{TabletOrClamshellMode}"
-    enum="BooleanEnabled" expires_after="2025-10-08">
+    enum="BooleanEnabled" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2071,7 +2071,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SaveLocation.{TabletOrClamshellMode}"
-    enum="CaptureModeSaveToLocation" expires_after="2025-10-08">
+    enum="CaptureModeSaveToLocation" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2083,7 +2083,7 @@
 
 <histogram
     name="Ash.CaptureModeController.ScreenRecordingFileSize.{TabletOrClamshellMode}"
-    units="KB" expires_after="2025-10-08">
+    units="KB" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2096,7 +2096,7 @@
 
 <histogram
     name="Ash.CaptureModeController.ScreenRecordingLength.{TabletOrClamshellMode}"
-    units="seconds" expires_after="2025-10-08">
+    units="seconds" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2108,7 +2108,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.ScreenshotsPerDay" units="int"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2121,7 +2121,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.ScreenshotsPerWeek" units="int"
-    expires_after="2025-12-14">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2136,7 +2136,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SearchButtonPressed.{TabletOrClamshellMode}"
-    enum="Boolean" expires_after="2026-01-04">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2147,7 +2147,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SearchButtonShown.{TabletOrClamshellMode}"
-    enum="Boolean" expires_after="2026-01-04">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2158,7 +2158,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SearchResultClicked.{TabletOrClamshellMode}"
-    enum="Boolean" expires_after="2026-01-04">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2169,7 +2169,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SearchResultsPanelEntryPoint.{TabletOrClamshellMode}"
-    enum="SearchResultsPanelEntryType" expires_after="2025-12-07">
+    enum="SearchResultsPanelEntryType" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2182,7 +2182,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SearchResultsPanelShown.{TabletOrClamshellMode}"
-    enum="Boolean" expires_after="2026-01-11">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2193,7 +2193,7 @@
 </histogram>
 
 <histogram name="Ash.CaptureModeController.SwitchesFromInitialCaptureMode"
-    enum="Boolean" expires_after="2025-10-08">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2205,7 +2205,7 @@
 
 <histogram
     name="Ash.CaptureModeController.SwitchToDefaultReason.{TabletOrClamshellMode}"
-    enum="CaptureModeSwitchToDefaultReason" expires_after="2025-10-08">
+    enum="CaptureModeSwitchToDefaultReason" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2218,7 +2218,7 @@
 
 <histogram
     name="Ash.CaptureModeController.{Client}.AudioRecordingMode.{TabletOrClamshellMode}"
-    enum="AudioRecordingMode" expires_after="2025-10-08">
+    enum="AudioRecordingMode" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2233,7 +2233,7 @@
 
 <histogram
     name="Ash.CaptureModeController.{Client}.CaptureConfiguration.{TabletOrClamshellMode}"
-    enum="CaptureModeConfiguration" expires_after="2025-12-07">
+    enum="CaptureModeConfiguration" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2261,7 +2261,7 @@
 
 <histogram
     name="Ash.CaptureModeController.{Client}.RecordingStartsWithCamera.{TabletOrClamshellMode}"
-    enum="BooleanEnabled" expires_after="2025-10-08">
+    enum="BooleanEnabled" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2274,7 +2274,7 @@
 
 <histogram
     name="Ash.CaptureModeController.{Client}.ScreenRecordingLength.{TabletOrClamshellMode}"
-    units="seconds" expires_after="2025-12-07">
+    units="seconds" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2289,9 +2289,8 @@
 
 <histogram name="Ash.ContentTransfer.AuthenticationResult"
     enum="ContentTransferAuthenticationResult" expires_after="2025-10-07">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
-  <owner>amberhaynes@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the outcome of webview authentication when it finishes. Allows for
@@ -2301,9 +2300,8 @@
 
 <histogram name="Ash.ContentTransfer.FlowState" enum="ContentTransferFlowState"
     expires_after="2025-10-07">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
-  <owner>amberhaynes@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the state at which the Content Transfer app was exited by the user.
@@ -2314,9 +2312,8 @@
 
 <histogram name="Ash.ContentTransfer.ShowNudgeFailed"
     enum="ContentTransferShowNudgeFailureReason" expires_after="2025-10-07">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
-  <owner>amberhaynes@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Recorded when showing the Content Transfer app nudge to a user has failed.
@@ -2389,7 +2386,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AnimationLatency.DeskActivation" units="ms"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2401,7 +2398,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AnimationLatency.DeskRemoval" units="ms"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2413,7 +2410,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AnimationSmoothness.DeskActivation" units="%"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
@@ -2426,7 +2423,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AnimationSmoothness.DeskEndGesture" units="%"
-    expires_after="2025-07-01">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2438,7 +2435,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AnimationSmoothness.DeskRemoval" units="%"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2451,7 +2448,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AssignToAllDesksSource"
-    enum="DesksAssignToAllDesksSource" expires_after="2026-03-25">
+    enum="DesksAssignToAllDesksSource" expires_after="2026-05-21">
   <owner>zxdan@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2465,7 +2462,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.CloseAllTotal" enum="BooleanHit"
-    expires_after="2025-12-14">
+    expires_after="2026-05-21">
   <owner>aprilzhou@google.com</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2478,18 +2475,19 @@
 </histogram>
 
 <histogram name="Ash.Desks.CloseAllUndo" enum="BooleanHit"
-    expires_after="2025-02-10">
+    expires_after="2026-05-21">
   <owner>aprilzhou@google.com</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emitted after a virtual desk being removed with close all option and undo
-    toast being clicked.
+    toast being clicked. Warning: this histogram was expired from 2025-02-10 to
+    2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Desks.ConsecutiveDailyVisits" units="days"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2506,7 +2504,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNameCount" units="desks"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2517,7 +2515,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNameCreated" enum="BooleanHit"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2528,7 +2526,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNamePercentage" units="%"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2539,7 +2537,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.DeskBar.Enter.PresentationTime"
-    units="ms" expires_after="2026-01-11">
+    units="ms" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2551,7 +2549,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.DeskBar.Exit.PresentationTime" units="ms"
-    expires_after="2026-01-11">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2563,7 +2561,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.HiddenByUser" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2574,7 +2572,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.Presses" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2586,7 +2584,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskLifetime_{DeskIndex}" units="hr"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2609,7 +2607,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DesksCount3" units="units"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2620,7 +2618,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DesksSwitch" enum="DesksSwitchSource"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2635,7 +2633,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DesksSwitchScreenshotResult" enum="BooleanSuccess"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2644,7 +2642,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.MoveWindowFromActiveDesk"
-    enum="DesksMoveWindowFromActiveDeskSource" expires_after="2025-12-07">
+    enum="DesksMoveWindowFromActiveDeskSource" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2661,7 +2659,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NewDesk2" enum="DesksCreationRemovalSource"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2672,7 +2670,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfDeskTraversals" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2685,7 +2683,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsClosed2" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2697,7 +2695,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsClosed2.{RemovalSource}"
-    units="windows" expires_after="2025-10-08">
+    units="windows" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2714,7 +2712,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_1" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2725,7 +2723,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_10" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2736,7 +2734,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_11" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2747,7 +2745,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_12" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2758,7 +2756,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_13" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2769,7 +2767,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_14" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2780,7 +2778,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_15" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2791,7 +2789,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_16" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2802,7 +2800,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_2" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2813,7 +2811,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_3" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2824,7 +2822,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_4" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2835,7 +2833,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_5" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2846,7 +2844,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_6" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2857,7 +2855,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_7" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2868,7 +2866,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_8" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2879,7 +2877,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_9" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2890,7 +2888,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.PresentationTime.UpdateGesture" units="ms"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2904,7 +2902,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.PresentationTime.UpdateGesture.MaxLatency"
-    units="ms" expires_after="2025-10-08">
+    units="ms" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2919,7 +2917,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.RemoveDesk" enum="DesksCreationRemovalSource"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2930,18 +2928,20 @@
 </histogram>
 
 <histogram name="Ash.Desks.RemoveDeskType" enum="DeskCloseType"
-    expires_after="2024-07-21">
+    expires_after="2026-05-21">
   <owner>aprilzhou@google.com</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emitted when a virtual desk is removed to specify the category of this
     remove operation among close all, combine desk, and close all and wait.
+    Warning: this histogram was expired from 2024-07-21 to 2025-07-21; data may
+    be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Desks.WeeklyActiveDesks" units="active desks"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2958,7 +2958,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.{EntryPoint}.BarAction.{BarAction}"
-    enum="BooleanHit" expires_after="2025-12-07">
+    enum="BooleanHit" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2985,7 +2985,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTamplate.LaunchAdminTemplate" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wms@google.com</owner>
@@ -2993,7 +2993,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.AddOrUpdateTemplateStatus"
-    enum="DeskModelAddOrUpdateEntryStatus" expires_after="2025-12-07">
+    enum="DeskModelAddOrUpdateEntryStatus" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3004,7 +3004,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.AdminTemplateTabCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3013,7 +3013,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.AdminTemplateWindowCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3022,7 +3022,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.DeleteSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3031,7 +3031,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.DeleteTemplate" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Recorded when desk templates are deleted, is never false.</summary>
@@ -3087,7 +3087,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.LaunchFromTemplate" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3096,14 +3096,14 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.LaunchSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Emitted when a Save and Recall desk is launched.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.LoadTemplateGrid" enum="BooleanHit"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3112,14 +3112,14 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.NewSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Recorded when a new Save and Recall desk is created.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.NewTemplate" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3128,14 +3128,14 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.ReplaceSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Recorded when the user replaces a Save and Recall desk.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.ReplaceTemplate" enum="BooleanHit"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3144,7 +3144,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallLocalDeskSavedDeskParseError"
-    enum="SavedDeskParseError" expires_after="2025-10-08">
+    enum="SavedDeskParseError" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>yzd@google.com</owner>
@@ -3152,7 +3152,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallTabCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3161,7 +3161,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallTemplateSize" units="B"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3171,7 +3171,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallUnsupportedAppDialogShow"
-    units="count" expires_after="2025-10-08">
+    units="count" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3183,7 +3183,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallWindowAndTabCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3193,7 +3193,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallWindowCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3202,7 +3202,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAsTemplatePressed" enum="BooleanHit"
-    expires_after="2025-08-12">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <summary>
@@ -3212,7 +3212,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SavedDeskButtonsShown" enum="BooleanHit"
-    expires_after="2025-08-12">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <summary>
@@ -3222,7 +3222,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SavedDeskMenuOptionsShown" enum="BooleanHit"
-    expires_after="2025-08-12">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <summary>
@@ -3233,7 +3233,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveForLaterPressed" enum="BooleanHit"
-    expires_after="2025-08-12">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <summary>
@@ -3243,7 +3243,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.ShowSavedDeskButtonsRevampDisabled"
-    enum="BooleanHit" expires_after="2025-08-12">
+    enum="BooleanHit" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <summary>
@@ -3252,7 +3252,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.ShowSavedDeskButtonsRevampEnabled"
-    enum="BooleanHit" expires_after="2025-08-12">
+    enum="BooleanHit" expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <summary>
@@ -3263,14 +3263,14 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TabCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Records the number of tabs in a template when it is saved.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TemplateSize" units="B"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3279,7 +3279,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TimeBetweenSaveAndRecall" units="seconds"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3289,7 +3289,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TimeToLoadTemplate" units="ms"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3299,7 +3299,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.UnsupportedAppDialogShow" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3311,7 +3311,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.UserSaveAndRecallCount" units="count"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3321,7 +3321,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.UserTemplateCount" units="count"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3331,7 +3331,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.WindowAndTabCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3340,7 +3340,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.WindowCount" units="count"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3396,25 +3396,27 @@
 </histogram>
 
 <histogram name="Ash.DragWindowFromShelf.PresentationTime" units="ms"
-    expires_after="2024-09-01">
+    expires_after="2026-05-21">
   <owner>tbarzic@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
     Presentation time in ms when a window is dragged from the bottom of the
     shelf. Recorded when the drag action is in progress.
 
-    Warning: this histogram was expired from 2022-10-04 to 2023-02-22; data may
+    Warning: this histogram was expired from 2024-09-01 to 2025-07-21; data may
     be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.DragWindowFromShelf.PresentationTime.MaxLatency"
-    units="ms" expires_after="2023-05-30">
+    units="ms" expires_after="2026-05-21">
   <owner>tbarzic@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
     Maximum latency of the presentation time in ms when a window is dragged from
-    the bottom of the shelf. Recorded when the drag action is finished.
+    the bottom of the shelf. Recorded when the drag action is finished. Warning:
+    this histogram was expired from 2023-05-30 to 2025-07-21; data may be
+    missing.
   </summary>
 </histogram>
 
@@ -3587,7 +3589,7 @@
 </histogram>
 
 <histogram name="Ash.Float.FloatWindowCountsPerSession" units="windows"
-    expires_after="2025-12-23">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -3599,7 +3601,7 @@
 </histogram>
 
 <histogram name="Ash.Float.FloatWindowDuration" units="minutes"
-    expires_after="2025-12-23">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
@@ -3613,7 +3615,7 @@
 </histogram>
 
 <histogram name="Ash.Float.FloatWindowMoveToAnotherDeskCounts" units="windows"
-    expires_after="2025-12-23">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
@@ -3623,7 +3625,7 @@
 </histogram>
 
 <histogram name="Ash.Float.MultitaskMenuActionType.{TabletOrClamshellMode}"
-    enum="MultitaskMenuActionType" expires_after="2025-12-07">
+    enum="MultitaskMenuActionType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
@@ -3633,7 +3635,7 @@
 </histogram>
 
 <histogram name="Ash.Float.MultitaskMenuEntryType.{TabletOrClamshellMode}"
-    enum="MultitaskMenuEntryType" expires_after="2025-12-07">
+    enum="MultitaskMenuEntryType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
@@ -4904,7 +4906,8 @@
 
 <histogram name="Ash.Login.ShowGaiaSignin.PermanentlyUntrusted" enum="Boolean"
     expires_after="2025-10-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records instances of a &quot;PERMANENTLY_UNTRUSTED&quot; result during the
@@ -4915,7 +4918,8 @@
 
 <histogram name="Ash.Login.ShowGaiaSignin.WaitTime" units="ms"
     expires_after="2025-11-30">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the amount of time spent waiting for trusted values before showing
@@ -5368,7 +5372,7 @@
 </histogram>
 
 <histogram name="Ash.MultiDisplay.WindowsMovedAfterRemap.DisplayRotated"
-    enum="Boolean" expires_after="2025-07-15">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>yunchengs@google.com</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -5383,7 +5387,7 @@
 
 <histogram
     name="Ash.MultiDisplay.WindowsMovedAfterRemap.DisplayWorkAreaChanged"
-    enum="Boolean" expires_after="2025-07-15">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>yunchengs@google.com</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -6137,7 +6141,7 @@
 
 <histogram
     name="Ash.Overview.AnimationSmoothness.Close.{TabletOrClamshellMode}"
-    units="%" expires_after="2025-08-24">
+    units="%" expires_after="2026-05-21">
   <owner>omrilio@chromium.org</owner>
   <owner>oshima@chromium.org</owner>
   <summary>
@@ -6148,7 +6152,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.AnimationSmoothness.Enter{OverviewAnimationMode}"
-    units="%" expires_after="2026-01-18">
+    units="%" expires_after="2026-05-21">
   <owner>achuith@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -6160,7 +6164,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.AnimationSmoothness.Exit{OverviewAnimationMode}"
-    units="%" expires_after="2026-01-18">
+    units="%" expires_after="2026-05-21">
   <owner>achuith@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -6173,18 +6177,20 @@
 </histogram>
 
 <histogram name="Ash.Overview.ArrowKeyPresses" units="units"
-    expires_after="2025-06-21">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
     The number of times the arrow keys are pressed in overview mode per session,
     i.e. between bringing up overview mode and ending it. This is only measured
-    for the sessions that end by selecting a window with the enter key.
+    for the sessions that end by selecting a window with the enter key. Warning:
+    this histogram was expired from 2025-06-21 to 2025-07-21; data may be
+    missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Overview.DelayedDeskBar.PresentationTime" units="ms"
-    expires_after="2026-01-11">
+    expires_after="2026-05-21">
   <owner>esum@google.com</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6200,7 +6206,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.DeskBarInitLatency" units="ms"
-    expires_after="2025-12-21">
+    expires_after="2026-05-21">
   <owner>esum@google.com</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -6232,7 +6238,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.EndAction" enum="OverviewEndAction"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -6248,7 +6254,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.Enter.PresentationTime2.{OverviewStartReason}"
-    units="ms" expires_after="2026-01-18">
+    units="ms" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>esum@google.com</owner>
@@ -6264,7 +6270,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.Exit.PresentationTime2" units="ms"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>esum@google.com</owner>
@@ -6276,7 +6282,7 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.Overview.Items" units="units" expires_after="2026-01-18">
+<histogram name="Ash.Overview.Items" units="units" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6286,7 +6292,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.KeyPressesOverItemsRatio" units="%"
-    expires_after="2025-07-15">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6297,7 +6303,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.OverviewClosedItems" units="units"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6307,7 +6313,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.Scroll.PresentationTime.MaxLatency.TabletMode"
-    units="ms" expires_after="2025-07-15">
+    units="ms" expires_after="2026-05-21">
   <owner>tclaiborne@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -6317,7 +6323,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.Scroll.PresentationTime.TabletMode" units="ms"
-    expires_after="2025-07-15">
+    expires_after="2026-05-21">
   <owner>tclaiborne@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -6328,7 +6334,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.SelectionDepth" units="items"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6339,7 +6345,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.StartAction" enum="OverviewStartAction"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -6355,7 +6361,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeBetweenActiveWindowChanges" units="seconds"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6367,7 +6373,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeBetweenUse" units="ms"
-    expires_after="2025-09-14">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6378,7 +6384,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeInOverview" units="ms"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6393,28 +6399,30 @@
 
 <histogram
     name="Ash.Overview.WindowDrag.PresentationTime.MaxLatency.{TabletOrClamshellMode}"
-    units="ms" expires_after="2025-04-11">
+    units="ms" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Maximum latency of the presentation time for dragging a window in overview
-    mode. {TabletOrClamshellMode}
+    mode. {TabletOrClamshellMode} Warning: this histogram was expired from
+    2025-04-11 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram
     name="Ash.Overview.WindowDrag.PresentationTime.{TabletOrClamshellMode}"
-    units="ms" expires_after="2025-04-11">
+    units="ms" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Presentation time for dragging a window in overview mode.
-    {TabletOrClamshellMode}
+    {TabletOrClamshellMode} Warning: this histogram was expired from 2025-04-11
+    to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Overview.WindowDrag.Workflow" enum="OverviewDragAction"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6710,7 +6718,7 @@
 </histogram>
 
 <histogram name="Ash.PhantomWindowController.Show.PresentationTime" units="ms"
-    expires_after="2025-07-15">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -6831,15 +6839,18 @@
 </histogram>
 
 <histogram name="Ash.Pine.DialogClosed" enum="ClosePineDialogType"
-    expires_after="2025-04-05">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>minch@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
-  <summary>Emitted whenever the informed restore dialog closes.</summary>
+  <summary>
+    Emitted whenever the informed restore dialog closes. Warning: this histogram
+    was expired from 2025-04-05 to 2025-07-21; data may be missing.
+  </summary>
 </histogram>
 
 <histogram name="Ash.Pine.DialogScreenshotVisibility" enum="Boolean"
-    expires_after="2025-12-14">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>minch@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -6851,7 +6862,7 @@
 </histogram>
 
 <histogram name="Ash.Pine.OnboardingDialog.TurnRestoreOn" enum="Boolean"
-    expires_after="2025-12-14">
+    expires_after="2026-05-21">
   <owner>hewer@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -6862,7 +6873,7 @@
 </histogram>
 
 <histogram name="Ash.Pine.ScreenshotDecodeDuration" units="ms"
-    expires_after="2025-12-14">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -6873,17 +6884,18 @@
 </histogram>
 
 <histogram name="Ash.Pine.ScreenshotEncodeAndSaveDuration" units="ms"
-    expires_after="2025-04-05">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     The amount of time it took to encode and save the screenshot to the disk
-    that we captured on shutdown.
+    that we captured on shutdown. Warning: this histogram was expired from
+    2025-04-05 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Pine.ScreenshotOnShutdownStatus"
-    enum="ScreenshotOnShutdownStatus" expires_after="2025-12-14">
+    enum="ScreenshotOnShutdownStatus" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -6894,18 +6906,19 @@
 </histogram>
 
 <histogram name="Ash.Pine.ScreenshotTakenDuration" units="ms"
-    expires_after="2025-04-05">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     The amount of time it took to capture a screenshot of the active desk on
     shutdown. This screenshot will only be taken if there are windows opened in
-    the desk.
+    the desk. Warning: this histogram was expired from 2025-04-05 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Pine.TimeToAction.{PineContentsType}" units="ms"
-    expires_after="2025-12-14">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -8346,7 +8359,7 @@
 </histogram>
 
 <histogram name="Ash.Snap.CloseTwoWindowsDuration" units="seconds"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8360,7 +8373,7 @@
 </histogram>
 
 <histogram name="Ash.Snap.MinimizeTwoWindowsDuration" units="seconds"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8375,7 +8388,7 @@
 </histogram>
 
 <histogram name="Ash.Snap.SnapTwoWindowsDuration" units="seconds"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8388,7 +8401,7 @@
 </histogram>
 
 <histogram name="Ash.SnapGroups.SnapGroupActualDuration" units="seconds"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8398,14 +8411,14 @@
 </histogram>
 
 <histogram name="Ash.SnapGroups.SnapGroupExitPoint" enum="SnapGroupExitPoint"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>Records the exit point of a Snap Group.</summary>
 </histogram>
 
 <histogram name="Ash.SnapGroups.SnapGroupPersistenceDuration" units="seconds"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8415,7 +8428,7 @@
 </histogram>
 
 <histogram name="Ash.SnapGroups.SnapGroupsCount" units="int"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8425,7 +8438,7 @@
 </histogram>
 
 <histogram name="Ash.SnapWindowSuggestions.{SnapSource}" enum="Boolean"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8449,7 +8462,7 @@
 </histogram>
 
 <histogram name="Ash.SplitView.DeviceOrientation.{DeviceUIMode}"
-    enum="DeviceOrientation" expires_after="2025-10-08">
+    enum="DeviceOrientation" expires_after="2026-05-21">
   <owner>zxdan@chromium.org</owner>
   <owner>fanafan@google.com</owner>
   <summary>
@@ -8464,19 +8477,20 @@
 </histogram>
 
 <histogram name="Ash.SplitView.EntryPoint.DeviceOrientation"
-    enum="DeviceOrientation" expires_after="2025-01-05">
+    enum="DeviceOrientation" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
     Emitted at the entry point of split view mode, to report the device
     orientation is in landscape mode (left and right) or portrait mode (top and
-    bottom).
+    bottom). Warning: this histogram was expired from 2025-01-05 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.SplitView.EntryPoint.DeviceUIMode" enum="DeviceMode"
-    expires_after="2025-10-30">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
@@ -8487,20 +8501,20 @@
 </histogram>
 
 <histogram name="Ash.SplitView.OrientationInSplitView" enum="DeviceOrientation"
-    expires_after="2025-03-11">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
     Emitted when device orientation changes in split view, to report the device
     orientation is in landscape mode (left and right) or portrait mode (top and
-    bottom). Warning: this histogram was expired from 2023-11-12 to 2024-03-11;
+    bottom). Warning: this histogram was expired from 2025-03-11 to 2025-07-21;
     data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.SplitView.ResizeWindowCount.{DeviceUIMode}" units="count"
-    expires_after="2025-10-30">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <summary>
@@ -8515,7 +8529,7 @@
 </histogram>
 
 <histogram name="Ash.SplitView.SwapWindowCount" units="count"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8525,19 +8539,20 @@
 </histogram>
 
 <histogram name="Ash.SplitView.TimeInMultiDisplaySplitView" units="ms"
-    expires_after="2025-05-21">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     The amount of time that the user spent in multi-display split view mode,
     meaning that split view is active on more than one display. The time is
     measured from when the number of displays in split view becomes more than
-    one to when it drops back down to one.
+    one to when it drops back down to one. Warning: this histogram was expired
+    from 2025-05-21 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.SplitView.TimeInSplitView" units="ms"
-    expires_after="2025-06-22">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromim.org</owner>
   <summary>
@@ -8548,7 +8563,7 @@
 </histogram>
 
 <histogram name="Ash.SplitView.{EngagementTime}.{DeviceUIMode}" units="ms"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>fanafan@chromium.org</owner>
@@ -8569,7 +8584,7 @@
 </histogram>
 
 <histogram name="Ash.SplitViewOverviewSession.SelectedWindowIndex" units="int"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8580,7 +8595,7 @@
 
 <histogram
     name="Ash.SplitViewOverviewSession.WindowLayoutCompleteOnSessionExit.{TabletOrClamshellMode}"
-    enum="Boolean" expires_after="2025-10-08">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8591,7 +8606,7 @@
 </histogram>
 
 <histogram name="Ash.SplitViewOverviewSession.WindowListSize" units="int"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8602,7 +8617,7 @@
 
 <histogram
     name="Ash.SplitViewOverviewSession.{SnapSource}.ExitPoint.{TabletOrClamshellMode}"
-    enum="SplitViewOverviewSessionExitPoint" expires_after="2025-10-08">
+    enum="SplitViewOverviewSessionExitPoint" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8614,7 +8629,7 @@
 </histogram>
 
 <histogram name="Ash.SplitViewResize.AnimationSmoothness.DividerAnimation"
-    units="%" expires_after="2025-12-07">
+    units="%" expires_after="2026-05-21">
   <owner>dandersson@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -8626,7 +8641,7 @@
 
 <histogram
     name="Ash.SplitViewResize.PresentationTime.MaxLatency{SplitViewResizeModes}"
-    units="ms" expires_after="2025-10-08">
+    units="ms" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8637,7 +8652,7 @@
 </histogram>
 
 <histogram name="Ash.SplitViewResize.PresentationTime{SplitViewResizeModes}"
-    units="ms" expires_after="2025-10-08">
+    units="ms" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8840,7 +8855,7 @@
 </histogram>
 
 <histogram name="Ash.TouchView.LidAngle" units="degrees"
-    expires_after="2026-01-18">
+    expires_after="2026-05-21">
   <owner>oshima@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8852,7 +8867,7 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActive" units="ms"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8861,21 +8876,21 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActivePercentage" units="%"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>The proportion of time spent in TouchView during a session.</summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActiveTotal" units="minutes"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>The total time that TouchView is active during a session.</summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewInactive" units="ms"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -8885,7 +8900,7 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewInactiveTotal" units="minutes"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9357,7 +9372,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.CrossFade" units="%"
-    expires_after="2025-10-16">
+    expires_after="2026-05-21">
   <owner>wutao@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -9370,7 +9385,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.CrossFade.DragMaximize"
-    units="%" expires_after="2025-10-16">
+    units="%" expires_after="2026-05-21">
   <owner>wutao@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -9387,7 +9402,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.CrossFade.DragUnmaximize"
-    units="%" expires_after="2025-10-16">
+    units="%" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9401,7 +9416,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.Hide" units="%"
-    expires_after="2025-10-16">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9414,7 +9429,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.Minimize" units="%"
-    expires_after="2025-10-16">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9427,7 +9442,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.Snap" units="%"
-    expires_after="2025-10-16">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9441,7 +9456,7 @@
 </histogram>
 
 <histogram name="Ash.Window.AnimationSmoothness.Unminimize" units="%"
-    expires_after="2025-10-16">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9454,18 +9469,19 @@
 </histogram>
 
 <histogram name="Ash.Window.DragMaximized.NumberOfMisTriggers" units="units"
-    expires_after="2025-04-11">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
     Emitted when a window state is being destroyed. Records number of
     mis-triggers of the drag to maximize behavior for a window during its
-    lifetime.
+    lifetime. Warning: this histogram was expired from 2025-04-01 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Window.DragMaximized.Valid" enum="Boolean"
-    expires_after="2025-01-05">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
@@ -9473,12 +9489,13 @@
     Emits true if a window is dragged to maximized and stays maximized status
     over 5 seconds. If a window is dragged to maximized, but gets restored
     during 5 seconds, the drag to maximize behavior should be considered as
-    invalid and a mis-trigger.
+    invalid and a mis-trigger. Warning: this histogram was expired from
+    2025-01-05 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Window.PartialSplitDuration" units="minutes"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
@@ -9492,7 +9509,7 @@
 </histogram>
 
 <histogram name="Ash.Window.Snap.DeviceOrientation" enum="DeviceOrientation"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9502,7 +9519,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.DesksSwitchDistance" units="units"
-    expires_after="2025-10-08">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9514,7 +9531,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.Enter.PresentationTime" units="ms"
-    expires_after="2026-01-11">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9526,7 +9543,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.InitialMode" enum="AltTabMode"
-    expires_after="2026-01-04">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9537,7 +9554,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.Items" units="items"
-    expires_after="2025-12-28">
+    expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -9547,7 +9564,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.ModeSwitchSource"
-    enum="AltTabModeSwitchSource" expires_after="2025-12-07">
+    enum="AltTabModeSwitchSource" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9558,18 +9575,19 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.SameApp.DeskMode" enum="AltTabMode"
-    expires_after="2025-07-03">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emitted when same app window cycling ends, if and only if user had 2 or more
     desks and Bento is not disabled, to report the same-desk vs all-desk mode
-    selection.
+    selection. Warning: this histogram was expired from 2025-07-03 to
+    2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.WindowCycleController.SameApp.IsSameApp" enum="Boolean"
-    expires_after="2025-08-24">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9579,19 +9597,20 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.SameApp.SkippedWindows"
-    units="windows" expires_after="2025-07-03">
+    units="windows" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     The number of windows the user didn't have to tab through because they were
     using Alt-Backtick instead of Alt-Tab. Recorded as the number of
     non-same-app windows in the ending MRU list between the starting and chosen
-    window in the initial cycling direction.
+    window in the initial cycling direction. Warning: this histogram was expired
+    from 2025-07-03 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.WindowCycleController.SwitchMode" enum="AltTabMode"
-    expires_after="2025-12-07">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9602,7 +9621,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleController.TimeBetweenTaskSwitches"
-    units="seconds" expires_after="2025-10-26">
+    units="seconds" expires_after="2026-05-21">
   <owner>minch@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -9612,7 +9631,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleView.AnimationSmoothness.Container" units="%"
-    expires_after="2026-01-11">
+    expires_after="2026-05-21">
   <owner>yichenz@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9627,7 +9646,7 @@
 </histogram>
 
 <histogram name="Ash.WindowCycleView.AnimationSmoothness.Show" units="%"
-    expires_after="2026-01-11">
+    expires_after="2026-05-21">
   <owner>yichenz@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9642,12 +9661,13 @@
 </histogram>
 
 <histogram name="Ash.WindowDragFromShelfResult" enum="ShelfWindowDragResult"
-    expires_after="2023-10-08">
+    expires_after="2026-05-21">
   <owner>andrewxu@chromium.org</owner>
   <owner>tbarzic@chromium.org</owner>
   <summary>
     The final state after window drag gesture that started from the system shelf
-    in tablet mode.
+    in tablet mode. Warning: this histogram was expired from 2023-10-08 to
+    2025-07-21; data may be missing.
   </summary>
 </histogram>
 
@@ -9674,46 +9694,51 @@
 </histogram>
 
 <histogram name="Ash.Wm.MultiWindowResizerClick" enum="Boolean"
-    expires_after="2025-05-21">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits true if the resize widget is clicked to start the resizing while in
-    mulit-window resizing mode.
+    mulit-window resizing mode. Warning: this histogram was expired from
+    2025-05-21 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.MultiWindowResizerClickTwoWindowsSnapped"
-    enum="Boolean" expires_after="2025-05-21">
+    enum="Boolean" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits true if the resize widget is clicked to start the resizing while in
-    mulit-window resizing mode.
+    mulit-window resizing mode. Warning: this histogram was expired from
+    2025-05-21 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.MultiWindowResizerShow" enum="Boolean"
-    expires_after="2025-05-21">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits true if the resize widget shows on mouse hover on the ResizeWindows.
+    Warning: this histogram was expired from 2025-05-21 to 2025-07-21; data may
+    be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.MultiWindowResizerShowTwoWindowsSnapped" enum="Boolean"
-    expires_after="2025-05-21">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits true if the resize widget shows on mouse hover on the ResizeWindows
-    and the two windows of the ResizeWindows are snapped.
+    and the two windows of the ResizeWindows are snapped. Warning: this
+    histogram was expired from 2025-05-21 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.ActiveWindowAppType"
-    enum="WindowAppType" expires_after="2025-08-31">
+    enum="WindowAppType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9723,7 +9748,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.ActiveWindowSize"
-    enum="WindowSizeRange" expires_after="2025-08-31">
+    enum="WindowSizeRange" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9733,7 +9758,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.ActiveWindowState"
-    enum="WindowStateType" expires_after="2025-11-30">
+    enum="WindowStateType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9743,17 +9768,18 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.AllAppTypes" enum="WindowAppType"
-    expires_after="2025-06-29">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window states type of all opened
-    application windows.
+    application windows. Warning: this histogram was expired from 2025-06-29 to
+    2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.AllWindowSizes"
-    enum="WindowSizeRange" expires_after="2025-08-31">
+    enum="WindowSizeRange" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9763,7 +9789,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.AllWindowStates"
-    enum="WindowStateType" expires_after="2025-11-02">
+    enum="WindowStateType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9773,17 +9799,18 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.FreeformedWindowSizes"
-    enum="WindowSizeRange" expires_after="2025-06-29">
+    enum="WindowSizeRange" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window bounds type of freeformed
-    application windows.
+    application windows. Warning: this histogram was expired from 2025-06-29 to
+    2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutState.WindowNumbers" units="int"
-    expires_after="2025-11-02">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -9792,104 +9819,113 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateActiveWindowAppType"
-    enum="WindowAppType" expires_after="2025-02-26">
+    enum="WindowAppType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window states type of the active
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateActiveWindowSize"
-    enum="WindowSizeRange" expires_after="2025-02-26">
+    enum="WindowSizeRange" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window bounds type of the active
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateActiveWindowState"
-    enum="WindowStateType" expires_after="2025-02-26">
+    enum="WindowStateType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window states type of the active
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateAllAppTypes" enum="WindowAppType"
-    expires_after="2025-02-26">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window states type of all opened
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateAllWindowSizes" enum="WindowSizeRange"
-    expires_after="2025-02-26">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window bounds type of all opened
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateAllWindowStates"
-    enum="WindowStateType" expires_after="2025-02-26">
+    enum="WindowStateType" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window states type of all opened
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateFreeformedWindowSizes"
-    enum="WindowSizeRange" expires_after="2025-02-26">
+    enum="WindowSizeRange" expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the window bounds type of freeformed
     application windows. This metrics should be removed after M127 stable is
-    released.
+    released. Warning: this histogram was expired from 2025-02-26 to 2025-07-21;
+    data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowLayoutStateWindowNumbers" units="int"
-    expires_after="2025-02-26">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
     Emits every 30 minutes to report the number of opened application windows.
-    This metrics should be removed after M127 stable is released.
+    This metrics should be removed after M127 stable is released. Warning: this
+    histogram was expired from 2025-02-26 to 2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowSnapActionSource2" enum="WindowSnapActionSource"
-    expires_after="2025-03-11">
+    expires_after="2026-05-21">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm@chromium.org</owner>
   <summary>
     Emitted when a window is to be snapped. Records different ways for a user to
-    snap a window.
+    snap a window. Warning: this histogram was expired from 2025-03-11 to
+    2025-07-21; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Ash.Wm.WindowSplitting.DragDuration.PerNoSplit" units="ms"
-    expires_after="2025-09-20">
+    expires_after="2026-05-21">
   <owner>aluh@chromium.org</owner>
   <owner>homi@chromium.org</owner>
   <summary>
@@ -9898,7 +9934,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowSplitting.DragDuration.PerSplit" units="ms"
-    expires_after="2025-09-20">
+    expires_after="2026-05-21">
   <owner>aluh@chromium.org</owner>
   <owner>homi@chromium.org</owner>
   <summary>
@@ -9907,7 +9943,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowSplitting.DragType"
-    enum="WindowSplittingDragType" expires_after="2025-09-20">
+    enum="WindowSplittingDragType" expires_after="2026-05-21">
   <owner>aluh@chromium.org</owner>
   <owner>homi@chromium.org</owner>
   <summary>
@@ -9917,7 +9953,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowSplitting.PreviewsShownCount.PerNoSplit"
-    units="previews" expires_after="2025-09-20">
+    units="previews" expires_after="2026-05-21">
   <owner>aluh@chromium.org</owner>
   <owner>homi@chromium.org</owner>
   <summary>
@@ -9926,7 +9962,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowSplitting.PreviewsShownCount.PerSplit"
-    units="previews" expires_after="2025-09-20">
+    units="previews" expires_after="2026-05-21">
   <owner>aluh@chromium.org</owner>
   <owner>homi@chromium.org</owner>
   <summary>
@@ -9935,7 +9971,7 @@
 </histogram>
 
 <histogram name="Ash.Wm.WindowSplitting.SplitRegion"
-    enum="WindowSplittingSplitRegion" expires_after="2025-09-20">
+    enum="WindowSplittingSplitRegion" expires_after="2026-05-21">
   <owner>aluh@chromium.org</owner>
   <owner>homi@chromium.org</owner>
   <summary>Records the window region where a window is split.</summary>
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml
index 0fbe50c0..eb5dfcf 100644
--- a/tools/metrics/histograms/metadata/blink/enums.xml
+++ b/tools/metrics/histograms/metadata/blink/enums.xml
@@ -4748,7 +4748,7 @@
   <int value="4269" label="SharedStorageAPI_SelectURL_Method"/>
   <int value="4270" label="SharedStorageAPI_Run_Method"/>
   <int value="4271" label="ViewTimelineConstructor"/>
-  <int value="4272" label="H1UserAgentFontSizeInSectionApplied"/>
+  <int value="4272" label="OBSOLETE_H1UserAgentFontSizeInSectionApplied"/>
   <int value="4273" label="OBSOLETE_kV8PendingBeacon_Constructor"/>
   <int value="4274" label="OBSOLETE_kV8PendingBeacon_Url_AttributeGetter"/>
   <int value="4275" label="OBSOLETE_kV8PendingBeacon_Url_AttributeSetter"/>
@@ -6242,6 +6242,7 @@
   <int value="5609" label="CanvasFallbackElementContent"/>
   <int value="5610" label="AutofillMaybeSyntheticSelect"/>
   <int value="5611" label="AutofillSyntheticSelect"/>
+  <int value="5612" label="FetchRetry"/>
 </enum>
 
 <!-- LINT.ThenChange(//third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom:WebFeature) -->
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index e56b1bc..e5e5a3ae 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1651,7 +1651,7 @@
 </histogram>
 
 <histogram name="ChromeOS.FirmwareUpdateUi.{Source}.{Severity}UpdateCount"
-    units="updates" expires_after="2025-08-31">
+    units="updates" expires_after="2026-08-31">
   <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
@@ -2536,7 +2536,7 @@
 </histogram>
 
 <histogram name="ChromeOS.KeyPermissionsManager.Migration"
-    enum="KeyPermissionsManagerMigrationStatus" expires_after="2025-09-01">
+    enum="KeyPermissionsManagerMigrationStatus" expires_after="2026-03-01">
   <owner>miersh@google.com</owner>
   <owner>chromeos-commercial-networking@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
index 380a4f3..16dd6bc 100644
--- a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
@@ -949,7 +949,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.SnapWindowSuggestions" enum="BooleanToggled"
-    expires_after="2025-08-24">
+    expires_after="2026-05-21">
   <owner>sophiewen@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -959,7 +959,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.SunfishEnabled" enum="BooleanToggled"
-    expires_after="2025-10-25">
+    expires_after="2026-05-21">
   <owner>sophiewen@chromium.org</owner>
   <owner>curtismcmullan@google.com</owner>
   <summary>
@@ -992,7 +992,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.UserActionOnSearchResultsShown"
-    enum="OsSettingSearchBoxUserAction" expires_after="2025-09-03">
+    enum="OsSettingSearchBoxUserAction" expires_after="2026-07-23">
   <owner>wesokuhara@google.com</owner>
   <owner>xiaohuic@chromium.org</owner>
   <owner>cros-settings@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index c2bf51f..90a4adff 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -602,8 +602,7 @@
 </histogram>
 
 <histogram name="Compositing.Display.VizCodePath.{VizCodePathName}"
-    enum="Boolean" expires_after="2025-08-01">
-  <owner>harthuang@google.com</owner>
+    enum="Boolean" expires_after="2026-06-09">
   <owner>fangzhoug@chromium.org</owner>
   <owner>petermcneeley@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index de780c9..53354963 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -112,7 +112,7 @@
 <histogram name="ContentNotifications.ClientStatus.Enabled.ByProvider"
     enum="Boolean" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The status of the push notifications client toggle for Content.
   </summary>
@@ -121,7 +121,7 @@
 <histogram name="ContentNotifications.ClientStatus.Sports.ByProvider"
     enum="Boolean" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The status of the push notifications client toggle for Sports.
   </summary>
@@ -130,14 +130,14 @@
 <histogram name="ContentNotifications.DismissAction" enum="Boolean"
     expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>The user has dismissed a content notification.</summary>
 </histogram>
 
 <histogram name="ContentNotifications.EligibilityType"
     enum="ContentNotificationEligibilityType" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The Type of elegibility for a given user for the Content Notifications
     feature. Includes details about what UI entrypoint type the user is elegible
@@ -148,7 +148,7 @@
 <histogram name="ContentNotifications.Notification.Action"
     enum="ContentNotificationActionType" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Reports what actions has the user taken on a notification. This metric
     matches NAUs sent.
@@ -158,7 +158,7 @@
 <histogram name="ContentNotifications.NotificationActionUpload.Success"
     enum="Boolean" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     After a notification action upload, whether the request succeeded or failed.
   </summary>
@@ -167,7 +167,7 @@
 <histogram name="ContentNotifications.OpenURLAction.HasURL" enum="Boolean"
     expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     After a notification interaction, if the URL has successfully been parsed or
     if it has failed.
@@ -177,7 +177,7 @@
 <histogram name="ContentNotifications.Promo.Prompt.Action"
     enum="ContentNotificationPromptAction" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The action taken by the user in response to the Set Up List Content
     Notification OS notification permission prompt.
@@ -189,7 +189,7 @@
     enum="ContentNotificationPromoProvisionalEntrypoint"
     expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Provisional notifications were turned on from the Notifications Promo.
   </summary>
@@ -198,7 +198,7 @@
 <histogram name="ContentNotifications.Promo.Snackbar.Event"
     enum="ContentNotificationSnackbarEvent" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Log the Set Up List Content Notification confirmation snackbar events.
   </summary>
@@ -207,7 +207,7 @@
 <histogram name="ContentNotifications.Promo.TopOfFeed.Action"
     enum="ContentNotificationTopOfFeedPromoAction" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The action taken by the user in response to the Top of Feed Content
     Notifications promo.
@@ -217,7 +217,7 @@
 <histogram name="ContentNotifications.Promo.TopOfFeed.Event"
     enum="ContentNotificationTopOfFeedPromoAction" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     An event from the the Top of Feed Content Notifications promo.
   </summary>
@@ -226,7 +226,7 @@
 <histogram name="ContentNotifications.Registration.BrowserStateUnavailable"
     enum="Boolean" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     This logs if a SNo registration has not succeeded due to a BrowserState
     being unavailable at the time due to a Browser not being initialized.
@@ -236,7 +236,7 @@
 <histogram name="ContentNotifications.Settings.Action"
     enum="ContentNotificationSettingsAction" expires_after="2026-01-20">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The action taken by the user in the content notification settings view.
   </summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index ada1a77..49f016d 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -705,17 +705,6 @@
   </summary>
 </histogram>
 
-<histogram name="CustomTabs.PostMessage.OnMessage" enum="Boolean"
-    expires_after="2025-07-06">
-  <owner>sinansahin@google.com</owner>
-  <owner>jinsukkim@chromium.org</owner>
-  <owner>chrome-connective-tissue@google.com</owner>
-  <summary>
-    Android only. Recorded when the tab controlled by the CustomTabsSession
-    sends a postMessage. Always emits true.
-  </summary>
-</histogram>
-
 <histogram
     name="CustomTabs.PostMessage.RequestPostMessageChannelWithTargetOrigin"
     enum="Boolean" expires_after="2026-01-11">
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml
index 33011c8..a966e57d 100644
--- a/tools/metrics/histograms/metadata/enterprise/histograms.xml
+++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -3744,7 +3744,8 @@
 
 <histogram name="Enterprise.UserPolicyChromeOS.ChildUser.OAuthTokenError"
     enum="GoogleServiceAuthError" expires_after="2025-12-07">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>michaelpg@chromium.org</owner>
   <summary>Failure reason for OAuth token fetch for child user.</summary>
 </histogram>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 039cc3ee..7432acdd 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -2029,19 +2029,6 @@
   </token>
 </histogram>
 
-<histogram name="Extensions.ExtensionsWithPageActions" units="units"
-    expires_after="2025-07-07">
-  <owner>rdevlin.cronin@chromium.org</owner>
-  <owner>extensions-core@chromium.org</owner>
-  <summary>
-    The number of Extensions that have Page Actions. Measured once per profile
-    open for &quot;user profile&quot; (profiles where people can install
-    extensions, specifically profiles that can have non-component extensions
-    installed). Replaced previous version
-    (PageActionController.ExtensionsWithPageActions).
-  </summary>
-</histogram>
-
 <histogram name="Extensions.ExternalItemState" enum="ExternalItemState"
     expires_after="2023-07-07">
   <owner>anunoy@chromium.org</owner>
@@ -3805,17 +3792,6 @@
   </summary>
 </histogram>
 
-<histogram name="Extensions.LoadUserScript2" units="units"
-    expires_after="2025-04-20">
-  <owner>rdevlin.cronin@chromium.org</owner>
-  <owner>extensions-core@chromium.org</owner>
-  <summary>
-    The number of converted user scripts loaded at &quot;user profile&quot;
-    (profiles where people can install extensions, specifically profiles that
-    can have non-component extensions installed) open.
-  </summary>
-</histogram>
-
 <histogram name="Extensions.Management.SetEnabled.HasUserGesture"
     enum="Boolean" expires_after="2026-03-20">
   <owner>solomonkinard@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/families/histograms.xml b/tools/metrics/histograms/metadata/families/histograms.xml
index bb741e0..5cfc7fe 100644
--- a/tools/metrics/histograms/metadata/families/histograms.xml
+++ b/tools/metrics/histograms/metadata/families/histograms.xml
@@ -47,7 +47,8 @@
 
 <histogram name="AddSupervisionDialog.Enrollment"
     enum="AddSupervisionEnrollment" expires_after="2026-01-04">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the number of users who go through the Add Supervision process to
@@ -64,7 +65,8 @@
 
 <histogram name="AddSupervisionDialog.EnrollmentCompletedUserTime" units="ms"
     expires_after="2026-01-04">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Measures the amount of time in milliseconds for users to successfully enroll
@@ -75,7 +77,8 @@
 
 <histogram name="AddSupervisionDialog.EnrollmentNotCompletedUserTime"
     units="ms" expires_after="2026-01-04">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Measures the amount of time in milliseconds for users to exit the Add
@@ -87,7 +90,8 @@
 
 <histogram name="AddSupervisionDialog.SignoutCompletedUserTime" units="ms"
     expires_after="2026-01-04">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Measures the amount of time in milliseconds for users to sign out after
@@ -98,7 +102,8 @@
 
 <histogram name="ChildAccountReconcilor.ForcedUserExitOnReconcileError"
     enum="BooleanHit" expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Number of forced logouts for child accounts on an account reconciliation
@@ -108,7 +113,8 @@
 
 <histogram name="ChromeOS.FamilyLink.ChildStatusReportRequest.Size" units="KB"
     expires_after="2026-01-04">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Reports the size of the uploaded ChildStatusReportRequest proto in
@@ -120,7 +126,8 @@
 <histogram
     name="ChromeOS.FamilyLink.ChildStatusReportRequest.TimeSinceLastReport"
     units="minutes" expires_after="2026-01-04">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Reports the time in between ChildStatusReportRequest uploads in minutes. The
@@ -132,7 +139,8 @@
 
 <histogram name="ChromeOS.FamilyLinkUser.FaviconAvailability"
     enum="SupervisedUserFaviconAvailability" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records whether the favicon is available when it is being requested. The
@@ -146,8 +154,8 @@
     enum="SupervisedUserLogSegment" expires_after="never">
 <!-- expires-never: used internally for filtering -->
 
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <owner>chrome-metrics-team@google.com</owner>
   <summary>
@@ -159,7 +167,8 @@
 
 <histogram name="ChromeOS.FamilyLinkUser.ParentAccess.FlowResult.{FlowType}"
     enum="ParentAccessFlowResult" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the state at which the Parent Access dialog is closed for all parent
@@ -177,7 +186,8 @@
 
 <histogram name="ChromeOS.FamilyLinkUser.ParentAccessWidgetError.{FlowType}"
     enum="FamilyLinkUserParentAccessWidgetError" expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records an error that occurs in the parent access widget. ChromeOS Only.
@@ -195,7 +205,8 @@
     name="ChromeOS.FamilyLinkUser.ParentAccessWidgetShowDialogError.{FlowType}"
     enum="FamilyLinkUserParentAccessWidgetShowDialogError"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records an error where the parent access widget dialog cannot be shown.
@@ -214,8 +225,8 @@
     expires_after="never">
 <!-- expires-never: used internally for filtering -->
 
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <owner>chrome-metrics-team@google.com</owner>
   <summary>
@@ -233,7 +244,8 @@
 
 <histogram name="ChromeOS.FamilyUser.NumSecondaryAccounts" units="accounts"
     expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <owner>chrome-metrics-team@google.com</owner>
   <summary>
@@ -245,7 +257,8 @@
 
 <histogram name="ChromeOS.LegacySupervisedUsers.HiddenFromLoginScreen"
     enum="LegacySupervisedUserStatus" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Reports &quot;hidden&quot; when the login screen hides a legacy supervised
@@ -257,7 +270,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.AppRemoval"
     enum="OnDeviceControlsAppRemoval" expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the success or failure of removing the oldest uninstalled app that
@@ -268,7 +282,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.BlockAppAction"
     enum="OnDeviceControlsBlockAppAction" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Recorded when the user interacts with apps with respect to on-device
@@ -280,7 +295,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.BlockedAppDialogShown"
     enum="OnDeviceControlsBlockedAppDialog" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Recorded when the user attempts to open an app blocked by on-device controls
@@ -290,7 +306,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.BlockedAppsCount" units="Apps"
     expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the number of apps blocked by on-device parental controls that a
@@ -300,7 +317,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.BlockedAppsEngagement" units="Apps"
     expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the number of apps blocked with on-device parental controls that a
@@ -310,7 +328,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.DialogAction.{DialogType}"
     enum="OnDeviceControlsDialogAction" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records user interactions with the dialogs in OS settings related to the
@@ -326,7 +345,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.PinDialogError"
     enum="OnDeviceControlsPinDialogError" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records if the user encounters an error when verifying or setting up a PIN
@@ -336,7 +356,8 @@
 
 <histogram name="ChromeOS.OnDeviceControls.PinSetupCompleted" enum="Boolean"
     expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records whether the user has set up a PIN for on-device app parental
@@ -471,7 +492,8 @@
 
 <histogram name="FamilyUser.ChromeBrowserEngagement.Duration2" units="ms"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the Chrome OS user Chrome browser usage in milliseconds. Reports
@@ -486,7 +508,8 @@
 
 <histogram name="FamilyUser.DeviceOwner" enum="Boolean"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records whether the current primary user is the owner of device. Reports at
@@ -496,7 +519,8 @@
 
 <histogram name="FamilyUser.FamilyLinkUsersCount" units="Number of Users"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the number of family link users on a Chrome OS device at the
@@ -506,7 +530,8 @@
 
 <histogram name="FamilyUser.GaiaUsersCount" units="Number of Users"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the number of Gaia users on a Chrome OS device, at the beginning of
@@ -517,7 +542,8 @@
 
 <histogram name="FamilyUser.ManagedSiteList" enum="FamilyLinkManagedSiteList"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records whether managed sites approved list and blocked list are enabled for
@@ -553,7 +579,8 @@
 
 <histogram name="FamilyUser.ManagedSiteListCount.Approved"
     units="Number of approved sites" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records number of approved urls and hosts for currently active Family Link
@@ -565,7 +592,8 @@
 
 <histogram name="FamilyUser.ManagedSiteListCount.Blocked"
     units="Number of blocked sites" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records number of blocked urls and hosts for currently active Family Link
@@ -577,7 +605,8 @@
 
 <histogram name="FamilyUser.NewUserAdded" enum="NewUserAdded"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Reports NewUserAdded enum when a new Family Link user or regular user is
@@ -588,7 +617,8 @@
 
 <histogram name="FamilyUser.SessionEngagement.Duration" units="ms"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the Chrome OS user session duration in milliseconds. Reports current
@@ -599,7 +629,8 @@
 
 <histogram name="FamilyUser.SessionEngagement.Total" units="Hour of day"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the Chrome OS user engagement hour within the current day (0-23),
@@ -611,7 +642,8 @@
 
 <histogram name="FamilyUser.SessionEngagement.Weekday" units="Hour of day"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the Chrome OS user engagement hour of day (0-23) on weekday. Logged
@@ -622,7 +654,8 @@
 
 <histogram name="FamilyUser.SessionEngagement.Weekend" units="Hour of day"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the Chrome OS user engagement hour of day (0-23) on weekend. Logged
@@ -633,7 +666,8 @@
 
 <histogram name="FamilyUser.TimeLimitPolicyTypes" enum="TimeLimitPolicyType"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records what time limit policy types are enabled for the currently active
@@ -647,7 +681,8 @@
 
 <histogram name="FamilyUser.WebFilterType" enum="FamilyLinkWebFilterType"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the web filter type for currently active Family Link user. Prior to
@@ -662,7 +697,8 @@
 <histogram name="FamilyUser.WebFilterType.PerRecord"
     enum="FamilyLinkWebFilterType" expires_after="2025-12-21">
   <owner>fernandex@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
@@ -679,7 +715,8 @@
 
 <histogram name="FamilyUser.{AppType}AppsCount2" units="Number of Apps"
     expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Around once per day, records the number of recently used {AppType} apps in
@@ -702,7 +739,8 @@
 
 <histogram name="FamilyUser.{ExtensionStatus}ExtensionsCount2"
     units="Number of Extensions" expires_after="2025-12-28">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <summary>
@@ -721,14 +759,16 @@
 
 <histogram name="ManagedMode.BlockingInterstitialCommand"
     enum="ManagedModeBlockingCommand" expires_after="2026-01-04">
-  <owner>agawronska@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>Which command was selected from the blocking interstitial.</summary>
 </histogram>
 
 <histogram name="ManagedUsers.BlockedIframeCount" units="iframes"
     expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The number of blocked iframes per unblocked main frame load. The value is
@@ -738,7 +778,8 @@
 
 <histogram name="ManagedUsers.FilteringResult"
     enum="SupervisedUserSafetyFilterResult" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The counts of results from supervised user URL filtering. Each entry
@@ -750,7 +791,8 @@
 
 <histogram name="ManagedUsers.RequestPermissionSource"
     enum="ManagedUserURLRequestPermissionSource" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The counts of request for permission sent from main frame or sub-frame.
@@ -899,8 +941,8 @@
 
 <histogram name="SupervisedUsers.ExtensionEnablement"
     enum="SupervisedUserExtensionEnablement" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records supervised users trying to enable or disable extensions. Enabled
@@ -915,8 +957,8 @@
 
 <histogram name="SupervisedUsers.ExtensionInstallDialog"
     enum="SupervisedUserExtensionInstallDialog" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the actions of supervised users on the Extension Install Dialog.
@@ -941,8 +983,8 @@
 
 <histogram name="SupervisedUsers.Extensions2" enum="SupervisedUserExtension2"
     expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <summary>
@@ -978,8 +1020,8 @@
 
 <histogram name="SupervisedUsers.ParentPermissionDialog"
     enum="SupervisedUserParentPermissionDialog" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the actions of parents on the Parent Permission Dialog. Opened count
@@ -996,7 +1038,8 @@
 
 <histogram name="SupervisedUsers.PerAppTimeLimits.AppsWithTimeLimit"
     units="Apps" expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The count of applications with time limit set by parents. Recorded once per
@@ -1006,7 +1049,8 @@
 
 <histogram name="SupervisedUsers.PerAppTimeLimits.BlockedAppsCount"
     units="Apps" expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The count of applications blocked by parents. It only applies to ARC++
@@ -1016,7 +1060,8 @@
 
 <histogram name="SupervisedUsers.PerAppTimeLimits.Engagement" units="Apps"
     expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Per-App Time Limits feature engagement measured by the number of apps with
@@ -1027,7 +1072,8 @@
 
 <histogram name="SupervisedUsers.PerAppTimeLimits.PolicyChangeCount"
     units="Changes" expires_after="2025-11-01">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The total number of PerAppTimeLimits policy changes seen in a session.
@@ -1037,7 +1083,8 @@
 
 <histogram name="SupervisedUsers.SitesMayRequestCameraMicLocation.PerRecord"
     enum="SupervisedUserToggleState" expires_after="2025-11-01">
-  <owner>courtneywong@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Records the state of the &quot;Permissions for sites&quot; toggle. When
@@ -1072,7 +1119,8 @@
 
 <histogram name="Supervision.ParentAccessCode.Action"
     enum="ParentAccessCodeAction" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Action originated in parent access code dialog. Logged every time the action
@@ -1082,7 +1130,8 @@
 
 <histogram name="Supervision.ParentAccessCode.Usage"
     enum="ParentAccessCodeUsage" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The context in which parent access code was used. Logged every time the new
@@ -1092,7 +1141,8 @@
 
 <histogram name="Supervision.ParentAccessCode.ValidationResult.{Action}"
     enum="ParentAccessCodeValidationResult" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The result of the parent access code validation for {Action} action. Logged
@@ -1110,7 +1160,8 @@
 
 <histogram name="Supervision.StatusReport.Event"
     enum="SupervisionStatusReportEvent" expires_after="2026-01-04">
-  <owner>agawronska@chromium.org</owner>
+  <owner>zhangwenyu@google.com</owner>
+  <owner>longbowei@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     The event that triggered status report for supervised account.
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml
index 56dcebb..45156b3 100644
--- a/tools/metrics/histograms/metadata/glic/histograms.xml
+++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -74,6 +74,7 @@
     <variant name="DetachPanel"/>
     <variant name="DropScrollToHighlight"/>
     <variant name="EnableDragResize"/>
+    <variant name="GetContextForActorFromTab"/>
     <variant name="GetContextFromFocusedTab"/>
     <variant name="GetContextFromTab"/>
     <variant name="GetModelQualityClientId"/>
@@ -326,6 +327,26 @@
   </summary>
 </histogram>
 
+<histogram name="Glic.Host.LoadingStageDuration.{LoadingStage}" units="ms"
+    expires_after="2026-07-21">
+  <owner>iwells@chromium.org</owner>
+  <owner>harringtond@chromium.org</owner>
+  <summary>
+    Records the amount of time a particular loading step took to complete.
+    {LoadingStage}
+  </summary>
+<!-- LINT.IfChange(LoadingStage) -->
+
+  <token key="LoadingStage">
+    <variant name="AwaitingCookieSync"/>
+    <variant name="AwaitingNotifyPanelWillOpen"/>
+    <variant name="AwaitingProfileReady"/>
+    <variant name="LoadingWebClient"/>
+  </token>
+<!-- LINT.ThenChange(//chrome/browser/resources/glic/glic_app_controller.ts:LoadingStage) -->
+
+</histogram>
+
 <histogram name="Glic.Host.WebClientState.{Event}"
     enum="GlicDetailedWebClientState" expires_after="2026-01-15">
   <owner>harringtond@chromium.org</owner>
@@ -374,6 +395,15 @@
   </summary>
 </histogram>
 
+<histogram name="Glic.MaybeReplaceNavigation.Result" enum="Boolean"
+    expires_after="2026-01-15">
+  <owner>liberato@chromium.org</owner>
+  <summary>
+    Records the boolean result of calling MaybeReplaceNavigation. This is used
+    to determine if a navigation was replaced with a media viewer.
+  </summary>
+</histogram>
+
 <histogram name="Glic.Metrics.Error" enum="GlicMetricsError"
     expires_after="2026-01-15">
   <owner>dewittj@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index 5f22933a..2889e7f00 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -228,7 +228,7 @@
 <histogram name="IOS.AppStoreRating.UserIsEligible" enum="Boolean"
     expires_after="2024-07-14">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logged once per app foreground. Logs whether the user has met the trigger
     requirements for the App Store Rating promo.
@@ -334,7 +334,7 @@
     enum="IOSBringAndroidTabsPromptActionType" expires_after="2026-01-04">
   <owner>hiramahmood@google.com</owner>
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The action taken by the user after the Bring Android Tabs prompt is
     presented.
@@ -345,7 +345,7 @@
     enum="IOSBringAndroidTabsTabsListActionType" expires_after="2024-08-25">
   <owner>hiramahmood@google.com</owner>
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The action taken by the user in response to the Bring Android Tabs Tab List
     .
@@ -356,7 +356,7 @@
     expires_after="2024-08-25">
   <owner>hiramahmood@google.com</owner>
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The number of tabs deselected from the Tab List View of the Bring Android
     Tabs prompt. Recorded after the Tab List View is dismissed.
@@ -367,7 +367,7 @@
     enum="IOSPromptAndroidTabsStatus" expires_after="2025-01-05">
   <owner>hiramahmood@google.com</owner>
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The result of prompting the set of tabs for an Android switcher. Recorded
     after the set of tabs are prompted. Starting M116, this metric would be
@@ -379,7 +379,7 @@
     expires_after="2025-04-20">
   <owner>hiramahmood@google.com</owner>
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The number of tabs imported from Android for Android Switchers. Recorded
     when the Bring Android Tabs prompt is displayed.
@@ -1197,7 +1197,7 @@
     enum="IOSDefaultBrowserFullscreenPromoAction" expires_after="2025-12-07">
   <owner>sebsg@chromium.org</owner>
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <owner>bling-mony-pod@google.com</owner>
   <summary>
     The action taken by the user in response to the Set Up List default browser
@@ -1711,7 +1711,7 @@
 <histogram name="IOS.ExternalAction" enum="IOSExternalAction"
     expires_after="2026-01-31">
   <owner>nicolasmacbeth@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the action passed to Chrome for iOS using an external action URL.
   </summary>
@@ -1730,7 +1730,7 @@
 <histogram name="IOS.FeedHandlingError.{Action}" enum="Boolean"
     expires_after="2025-07-05">
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Emitted every time a request from Discover feed could not be fulfilled as
     intended.
@@ -1877,7 +1877,7 @@
 <histogram name="IOS.FirstRun.BestFeatures.MainScreen.Action"
     enum="IOSBestFeaturesMainScreenActionType" expires_after="2025-10-26">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Type of action user took on the initial/main screen of the Best Features
     Experience in the FRE.
@@ -1887,7 +1887,7 @@
 <histogram name="IOS.FirstRun.BestFeatures.{FeatureName}.Action"
     enum="IOSBestFeaturesDetailScreenActionType" expires_after="2025-10-26">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Type of action user took on the {FeatureName} detail screen of the Best
     Features Experience in the FRE.
@@ -2110,14 +2110,14 @@
 <histogram name="IOS.GuidedTour.DidFinishStep" enum="GuidedTourStep"
     expires_after="2026-05-30">
   <owner>thegreenfrog@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>Recorded when the user finishes a step in the Guided Tour.</summary>
 </histogram>
 
 <histogram name="IOS.GuidedTour.Promo.DidAccept" enum="Boolean"
     expires_after="2026-05-30">
   <owner>thegreenfrog@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records when the user is shown the Guided Tour modal promo and either
     decides to go through the tour or not.
@@ -2127,7 +2127,7 @@
 <histogram name="IOS.HomeCustomization.MagicStack.ParcelTracking.Enabled"
     enum="Boolean" expires_after="2025-12-14">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records whether the Parcel Tracking module is currently enabled in the Magic
     Stack from the Home Customization menu. Logged on each NTP impression.
@@ -2137,7 +2137,7 @@
 <histogram name="IOS.HomeCustomization.MagicStack.SafetyCheck.Enabled"
     enum="Boolean" expires_after="2025-10-12">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records whether the Safety Check module is currently enabled in the Magic
     Stack from the Home Customization menu. Logged on each NTP impression.
@@ -2147,7 +2147,7 @@
 <histogram name="IOS.HomeCustomization.MagicStack.SetUpList.Enabled"
     enum="Boolean" expires_after="2025-10-12">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records whether the Set Up List module is currently enabled in the Magic
     Stack from the Home Customization menu. Logged on each NTP impression.
@@ -2157,7 +2157,7 @@
 <histogram name="IOS.HomeCustomization.MagicStack.TabResumption.Enabled"
     enum="Boolean" expires_after="2025-10-12">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records whether the Tab Resumption module is currently enabled in the Magic
     Stack from the Home Customization menu. Logged on each NTP impression.
@@ -2168,7 +2168,7 @@
     expires_after="2025-10-12">
   <owner>bwwilliams@google.com</owner>
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records whether the Tips module is currently enabled in the Magic Stack from
     the Home Customization menu. Logged on each NTP impression.
@@ -2178,7 +2178,7 @@
 <histogram name="IOS.HomeCustomization.Opened"
     enum="IOSHomeCustomizationEntrypoint" expires_after="2025-12-14">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the entrypoint used to open the Home Customization menu. Logged
     whenever the Home Customization menu is opened.
@@ -2499,7 +2499,7 @@
 <!-- expires-never: Core metric to track how Chrome is launched -->
 
   <owner>sebsg@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>Records the way the app was launched on iOS.</summary>
 </histogram>
 
@@ -2546,7 +2546,7 @@
 <histogram name="IOS.MagicStack.Module.Click.MostVisited" units="index"
     expires_after="2025-09-28">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Most Visited Sites module when a user clicks
     on it.
@@ -2584,7 +2584,7 @@
 <histogram name="IOS.MagicStack.Module.Click.SafetyCheck" units="index"
     expires_after="2026-01-04">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Safety Check module when a user clicks on it.
   </summary>
@@ -2593,7 +2593,7 @@
 <histogram name="IOS.MagicStack.Module.Click.SendTabPromo" units="index"
     expires_after="2025-05-20">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Send Tab Promo module when a user taps on it.
   </summary>
@@ -2602,7 +2602,7 @@
 <histogram name="IOS.MagicStack.Module.Click.Shortcuts" units="index"
     expires_after="2026-01-18">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Shortcuts module when a user clicks on it.
   </summary>
@@ -2611,7 +2611,7 @@
 <histogram name="IOS.MagicStack.Module.Click.TabResumption" units="index"
     expires_after="2026-01-18">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Tab Resumption module when a user clicks on
     it.
@@ -2621,7 +2621,7 @@
 <histogram name="IOS.MagicStack.Module.Click.Tips" units="index"
     expires_after="2025-09-26">
   <owner>bwwilliams@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Tips module when a user clicks on it.
   </summary>
@@ -2630,7 +2630,7 @@
 <histogram name="IOS.MagicStack.Module.Disabled" enum="IOSMagicStackModuleType"
     expires_after="2025-11-23">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>Records when a module was disabled.</summary>
 </histogram>
 
@@ -2647,7 +2647,7 @@
     name="IOS.MagicStack.Module.{Event}.TabResumption.{Surface}.{Source}"
     units="index" expires_after="2026-01-11">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the rank index of the Tab Resumption module displaying a {Source}
     tab, if it is displaying on {Surface} on {Event} event.
@@ -2670,7 +2670,7 @@
 <histogram name="IOS.MagicStack.NTP.SegmentationRankingFetchTime" units="ms"
     expires_after="2025-12-14">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the fetch time for the Segmentation ranking for Magic Stack on NTP.
   </summary>
@@ -2679,7 +2679,7 @@
 <histogram name="IOS.MagicStack.ScrollActionToIndex" units="index"
     expires_after="2025-09-07">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the Magic Stack card index to which the user scrolled to each time a
     scroll to a new module happens.
@@ -2708,7 +2708,7 @@
 <histogram name="IOS.MagicStack.Start.SegmentationRankingFetchTime" units="ms"
     expires_after="2025-12-14">
   <owner>thegreenfrog@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the fetch time for the Segmentation ranking for Magic Stack on
     Start.
@@ -3185,7 +3185,7 @@
 <histogram name="IOS.Notification.Dismissed" enum="NotificationType"
     expires_after="2026-01-09">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when a notification was dismissed on a user's device. Will be logged
     when the user opens the app.
@@ -3195,7 +3195,7 @@
 <histogram name="IOS.Notification.Interaction" enum="NotificationType"
     expires_after="2026-01-09">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when a notification was interacted with on a user's device. Will be
     logged when the user opens the app.
@@ -3205,7 +3205,7 @@
 <histogram name="IOS.Notification.Received" enum="NotificationType"
     expires_after="2026-01-09">
   <owner>thegreenfrog@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when a notification was received on a user's device. Will be logged
     when the user opens the app, after the notification has been received.
@@ -3235,7 +3235,7 @@
     enum="IOSSafetyCheckNotificationType" expires_after="2026-01-18">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when a Safety Check notification that was triggered appears to have
     dismissed or cleared from the notification center. Will be logged when or if
@@ -3247,7 +3247,7 @@
     enum="IOSSafetyCheckNotificationType" expires_after="2025-11-23">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when the user interacts with a Safety Check notification.
   </summary>
@@ -3257,7 +3257,7 @@
     enum="IOSSafetyCheckNotificationsOptInSource" expires_after="2025-11-30">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs the source where the user opted in or opted out of receiving Safety
     Check notifications.
@@ -3268,7 +3268,7 @@
     enum="IOSSafetyCheckNotificationType" expires_after="2026-01-18">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when a Safety Check notification is requested to be sent to the user.
     Note: this does not indicate that the notification was received by the user,
@@ -3280,7 +3280,7 @@
     enum="IOSSafetyCheckNotificationType" expires_after="2026-01-18">
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs when a Safety Check notification that was requested appears to have
     triggered. Will be logged when or if the app starts again, after the
@@ -3292,7 +3292,7 @@
     name="IOS.Notifications.SendTab.MagicStack.AllowNotificationsPressed"
     enum="Boolean" expires_after="2025-09-13">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Recorded when a user taps on the 'Allow Notifications' button on the Send
     Tab Notifications Promo module in the Magic Stack.
@@ -3303,7 +3303,7 @@
     enum="PushNotificationSettingsAuthorizationStatus"
     expires_after="2025-11-23">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs the notification permission status when a Send Tab notification is
     received on the target device.
@@ -3396,7 +3396,7 @@
 <histogram name="IOS.NTP.Impression.CustomizationState"
     enum="IOSNTPImpressionCustomizationState" expires_after="2025-12-14">
   <owner>adamta@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The current visibility of NTP components chosen from the customization menu.
     Logged each time an NTP is made visible.
@@ -3827,7 +3827,7 @@
 <histogram name="IOS.ParcelTracking.OptInStatus"
     enum="IOSParcelTrackingOptInStatus" expires_after="2025-07-06">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs the opt-in status the user has given for whether or not they allow
     parcel tracking on the device. Logged once per app start. For users who have
@@ -4057,7 +4057,7 @@
     enum="IOSPostRestoreDefaultBrowserActionOnPrompt"
     expires_after="2025-01-26">
   <owner>hiramahmood@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs a user's action on the Post Restore Default Browser promo.
   </summary>
@@ -4067,7 +4067,7 @@
     enum="IOSPostRestoreSigninChoice" expires_after="2025-12-14">
   <owner>scottyoder@google.com</owner>
   <owner>jlebel@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs a user's choice when presented with the Post Restore Signin Promo.
     Note: this metric got expired for a while between 2024-03-31 and 2024-11-07.
@@ -4078,7 +4078,7 @@
     expires_after="2025-12-14">
   <owner>scottyoder@google.com</owner>
   <owner>jlebel@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Indicates whether the Post Restore Signin Promo was displayed. Note: this
     metric got expired for a while between 2024-03-31 and 2024-11-07.
@@ -4234,7 +4234,7 @@
 <histogram name="IOS.PushNotification.Client.Disabled"
     enum="PushNotificationClientId" expires_after="2026-01-18">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs that a particular Push Notification Client was disabled by the user.
   </summary>
@@ -4243,7 +4243,7 @@
 <histogram name="IOS.PushNotification.Client.Enabled"
     enum="PushNotificationClientId" expires_after="2026-01-18">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs that a particular Push Notification Client was enabled by the user.
   </summary>
@@ -4254,7 +4254,7 @@
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <owner>treib@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs the specific code path where obtaining the
     PushNotificationClientManager for the current Profile failed during
@@ -4331,7 +4331,7 @@
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <owner>treib@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the outcome of handling a push notification interaction in a
     multi-Profile environment. Tracks whether the correct target Profile handled
@@ -4377,7 +4377,7 @@
     enum="PushNotificationSettingsAuthorizationStatus"
     expires_after="2026-01-11">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Logs the push notification iOS settings permission status the user's device
     was previously in before their push notifications permission status changed
@@ -4419,7 +4419,7 @@
   <owner>bwwilliams@google.com</owner>
   <owner>scottyoder@google.com</owner>
   <owner>treib@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     Records the specific reason why creating a Profile-specific
     UNNotificationRequest failed within PushNotificationClient for the
@@ -5263,7 +5263,7 @@
 <histogram name="IOS.SetUpList.AllItemsCompleted" enum="Boolean"
     expires_after="2026-01-11">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     This histogram counts the number of times that all items in the Set Up List
     are completed.
@@ -5273,7 +5273,7 @@
 <histogram name="IOS.SetUpList.Displayed" enum="Boolean"
     expires_after="2025-12-28">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     This histogram counts the number of times the Set Up List is shown on the
     NTP.
@@ -5283,7 +5283,7 @@
 <histogram name="IOS.SetUpList.ItemCompleted" enum="IOSSetUpListItemType"
     expires_after="2025-12-28">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     This histogram counts the number of times Set Up List items are completed.
     It is recorded when the Set Up List item is marked complete in prefs, or
@@ -5295,7 +5295,7 @@
 <histogram name="IOS.SetUpList.ItemDisplayed" enum="IOSSetUpListItemType"
     expires_after="2025-12-14">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     This histogram counts the number of times Set Up List items are displayed.
   </summary>
@@ -5304,7 +5304,7 @@
 <histogram name="IOS.SetUpList.ItemSelected" enum="IOSSetUpListItemType"
     expires_after="2026-01-04">
   <owner>scottyoder@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     This histogram counts the number of times Set Up List items are selected.
   </summary>
@@ -5983,7 +5983,7 @@
     enum="VariationsFirstRunSeedApplicationStage" expires_after="2025-12-07">
   <owner>ginnyhuang@chromium.org</owner>
   <owner>huitingyu@google.com</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The stage of applying a downloaded initial variations seed during Chrome
     first run on platforms that implemented first run variations. This would be
@@ -5998,7 +5998,7 @@
 <histogram name="IOS.Variations.FirstRun.SeedFetchResult"
     enum="VariationsSeedFetchResult" expires_after="2025-12-28">
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The result of attempting to fetch an initial variations seed during iOS
     Chrome first run. Records both the HTTP code and various error values in one
@@ -6009,7 +6009,7 @@
 <histogram name="IOS.Variations.FirstRun.SeedFetchTime" units="ms"
     expires_after="2025-12-28">
   <owner>ginnyhuang@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The latency of fetching an initial variations seed during iOS Chrome first
     run. Only considers cases where an HTTP 200 result was received.
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index e215c1d..7581094 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -142,6 +142,12 @@
   <variant name="PassageEmbedder" summary="Text embedding for passages"/>
   <variant name="PasswordManagerFormClassification"
       summary="Classifies password forms"/>
+  <variant name="PermissionsAiv4GeolocationDesktop"
+      summary="Permissions: Use snapshot and visible page content text to
+               decide on relevance for a Geolocation permission request"/>
+  <variant name="PermissionsAiv4NotificationsDesktop"
+      summary="Permissions: Use snapshot and visible page content text to
+               decide on relevance for a Notifications permission request"/>
   <variant name="PhraseSegmentation" summary="Phrase segmentation"/>
   <variant name="PreloadingHeuristics" summary="Speculation-rule preloading"/>
   <variant name="SegmentationAdaptiveToolbar"
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 468378db..470b0e9 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -6020,73 +6020,6 @@
   </summary>
 </histogram>
 
-<histogram name="MixedAutoupgrade.ResourceRequest.ErrorOrResponseCode"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2023-08-13">
-  <owner>carlosil@chromium.org</owner>
-  <summary>
-    The net error or HTTP response code of a mixed content resource request that
-    was autoupgraded to HTTPS. This histogram was expired from M80 to M108.
-  </summary>
-</histogram>
-
-<histogram name="MixedAutoupgrade.ResourceRequest.Failure.IsAd" enum="Boolean"
-    expires_after="M112">
-  <owner>carlosil@chromium.org</owner>
-  <summary>
-    Whether or not an autoupgrade mixed content request was for a resource we
-    know to be an ad. This histogram was expired from M80 to M108.
-  </summary>
-</histogram>
-
-<histogram name="MixedAutoupgrade.ResourceRequest.Failure.Type"
-    enum="ResourceType" expires_after="M112">
-  <owner>carlosil@chromium.org</owner>
-  <owner>estark@chromium.org</owner>
-  <summary>
-    Logs the type of each resource request that is autoupgraded to HTTPS and
-    fails to load. This histogram was expired from M80 to M108.
-
-    Warning: an unexpected reorder happened in Apr 2021
-    (https://crrev.com/c/2798954). Please do not trust older reports.
-  </summary>
-</histogram>
-
-<histogram name="MixedAutoupgrade.ResourceRequest.Response.Type"
-    enum="ResourceType" expires_after="M112">
-  <owner>carlosil@chromium.org</owner>
-  <owner>estark@chromium.org</owner>
-  <summary>
-    Logs the type of each resource request that was autoupgraded to HTTPS and
-    resulted in a response. This histogram was expired from M80 to M108.
-
-    Warning: an unexpected reorder happened in Apr 2021
-    (https://crrev.com/c/2798954). Please do not trust older reports.
-  </summary>
-</histogram>
-
-<histogram name="MixedAutoupgrade.ResourceRequest.Start.Type"
-    enum="ResourceType" expires_after="M112">
-  <owner>carlosil@chromium.org</owner>
-  <owner>estark@chromium.org</owner>
-  <summary>
-    Logs the type of each resource request that is autoupgraded to HTTPS. This
-    is logged when the request is started. This histogram was expired from M80
-    to M108.
-
-    Warning: an unexpected reorder happened in Apr 2021
-    (https://crrev.com/c/2798954). Please do not trust older reports.
-  </summary>
-</histogram>
-
-<histogram name="MixedAutoupgrade.ResourceRequest.Status"
-    enum="MixedContentAutoupgradeStatus" expires_after="2023-08-08">
-  <owner>carlosil@chromium.org</owner>
-  <summary>
-    The status of a mixed content resource request that was autoupgraded to
-    HTTPS. This histogram was expired from M80 to M108.
-  </summary>
-</histogram>
-
 <histogram name="Mojo.Channel.WriteMessageLatency" units="ms"
     expires_after="2026-01-18">
   <owner>amistry@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 6097a58..df19b7b6 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -304,21 +304,6 @@
   </summary>
 </histogram>
 
-<histogram name="PageActionController.ExtensionsWithPageActions" units="units"
-    expires_after="2023-07-07">
-  <owner>rdevlin.cronin@chromium.org</owner>
-  <owner>extensions-core@chromium.org</owner>
-  <summary>
-    The number of Extensions that have Page Actions. Measured once per profile
-    open.
-
-    Histogram is in the process of being removed in in favor of
-    Extensions.ExtensionsWithPageActions that emits only on profile open for
-    &quot;user&quot; profiles (profiles where people can install extensions,
-    specifically profiles that can have non-component extensions installed).
-  </summary>
-</histogram>
-
 <histogram name="PageActionController.NumberActionsShown2" units="actions"
     expires_after="2025-12-14">
   <owner>emshack@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/password/enums.xml b/tools/metrics/histograms/metadata/password/enums.xml
index e27764f..d8070a26 100644
--- a/tools/metrics/histograms/metadata/password/enums.xml
+++ b/tools/metrics/histograms/metadata/password/enums.xml
@@ -492,23 +492,6 @@
   <int value="2" label="User typed or autofilled values"/>
 </enum>
 
-<enum name="LocalPwdMigrationProgressState">
-  <int value="0" label="Scheduled"/>
-  <int value="1" label="Started"/>
-  <int value="2" label="Finished"/>
-</enum>
-
-<enum name="LocalUpmActivationError">
-  <int value="0"
-      label="None (activated / migration scheduled / previously activated)"/>
-  <int value="1" label="(obsolete) Unenrolled from UPM"/>
-  <int value="2" label="(obsolete) Initial UPM migration missing"/>
-  <int value="3" label="(obsolete) Login DB file move failed"/>
-  <int value="4" label="Outdated GmsCore"/>
-  <int value="5" label="(obsolete) Flag disabled"/>
-  <int value="6" label="(obsolete) Migration warning unacknowledged"/>
-</enum>
-
 <enum name="LoginDatabaseEncryptionStatus">
   <int value="0" label="No issues"/>
   <int value="1"
@@ -648,7 +631,7 @@
   <int value="24" label="Passkey deleted confirmation bubble"/>
   <int value="25" label="Passkey updated confirmation bubble"/>
   <int value="26" label="Passkey not accepted confirmation bubble"/>
-  <int value="27" label="Password access loss warning"/>
+  <int value="27" label="(obsolete) Password access loss warning"/>
   <int value="28" label="Passkey upgrade bubble"/>
   <int value="29" label="Password change state information bubble"/>
 </enum>
@@ -665,14 +648,6 @@
   <int value="2" label="Invalid passkey"/>
 </enum>
 
-<enum name="PasswordAccessLossWarningType">
-  <int value="0" label="No warning"/>
-  <int value="1" label="No GMS Core"/>
-  <int value="2" label="No UPM"/>
-  <int value="3" label="Only Account UPM"/>
-  <int value="4" label="New GMS Core, migration failed"/>
-</enum>
-
 <enum name="PasswordAddLoginSyncError">
   <int value="0" label="None"/>
   <int value="1" label="DB Not Available"/>
@@ -1930,12 +1905,6 @@
   <int value="5" label="Client-side model prediction"/>
 </enum>
 
-<enum name="UseUpmLocalAndSeparateStoresState">
-  <int value="0" label="Off"/>
-  <int value="1" label="OffAndMigrationPending"/>
-  <int value="2" label="On"/>
-</enum>
-
 <enum name="WellKnownChangePasswordResult">
   <int value="0" label="Fallback to Origin"/>
   <int value="1" label="Fallback to Url Override"/>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index f3579d90..b94bf8d 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -22,17 +22,6 @@
 
 <histograms>
 
-<variants name="AccessLossWarningType">
-  <variant name="NewGmsCoreMigrationFailed"
-      summary="with new GMS Core version, but migration to UPM still failed"/>
-  <variant name="NoGmsCore" summary="without GMS Core installed"/>
-  <variant name="NoUPM"
-      summary="with GMS Core version that doesn't support UPM"/>
-  <variant name="OnlyAccountUpm"
-      summary="with GMS Core version that supports only UPM for account
-               passwords"/>
-</variants>
-
 <variants name="AccessorySheetType">
   <variant name="Addresses"/>
   <variant name="Passwords"/>
@@ -46,13 +35,6 @@
   <variant name=".WithoutCustomPassphrase" summary="regularly encrypted"/>
 </variants>
 
-<variants name="MigrationOperation">
-  <variant name="AddLogin"/>
-  <variant name="GetAllLogins"/>
-  <variant name="RemoveLogin"/>
-  <variant name="UpdateLogin"/>
-</variants>
-
 <variants name="PasswordAccountStorageUsageLevel">
   <variant name=""/>
   <variant name=".NotUsingAccountStorage"
@@ -2237,48 +2219,6 @@
   </summary>
 </histogram>
 
-<histogram name="PasswordManager.LocalUpmActivationError{UserType}"
-    enum="LocalUpmActivationError" expires_after="2025-12-28">
-  <owner>ioanap@chromium.org</owner>
-  <owner>src/components/password_manager/OWNERS</owner>
-  <summary>
-    Recorded for {UserType}. Records the reason why the local UPM activation
-    algorithm failed, if any. For users that require a migration, the
-    &quot;None&quot; bucket doesn't mean the migration actually succeeded, only
-    that it was scheduled. Recorded on every startup, even for users who already
-    got successfully activated. This histogram should be analyzed with
-    &quot;count unique clients&quot;.
-
-    TODO(crbug.com/307678344): Mention what other histogram should be used for
-    migration failures.
-  </summary>
-  <token key="UserType">
-    <variant name="" summary="all users"/>
-    <variant name=".NonSyncingNoMigration"
-        summary="users who are not syncing passwords and have no local
-                 passwords nor custom password manager settings to be
-                 migrated"/>
-    <variant name=".NonSyncingWithMigration"
-        summary="users who are not syncing passwords and need a migration for
-                 local passwords or password manager settings"/>
-    <variant name=".Syncing" summary="users who are syncing passwords"/>
-  </token>
-</histogram>
-
-<histogram name="PasswordManager.LocalUpmActivationStatus"
-    enum="UseUpmLocalAndSeparateStoresState" expires_after="2025-12-28">
-  <owner>ioanap@chromium.org</owner>
-  <owner>vsemeniuk@google.com</owner>
-  <summary>
-    Records on startup the exact state stored in the UPM local state pref,
-    immediately after the pref value is set. The main difference to
-    PasswordManager.LocalUpmActivated is that this histogram records the
-    &quot;migration pending&quot; state separately. This can be used to identify
-    whether thre are any issue that could cause clients to be stuck in migration
-    pending.
-  </summary>
-</histogram>
-
 <histogram name="PasswordManager.LoginDatabase.DeleteFromKeychain"
     enum="MacSecurityFrameworkOSStatus" expires_after="2025-12-14">
   <owner>vsemeniuk@google.com</owner>
@@ -2623,67 +2563,6 @@
   </summary>
 </histogram>
 
-<histogram name="PasswordManager.PasswordAccessLossWarningDialog.Shown"
-    enum="PasswordAccessLossWarningType" expires_after="2026-01-11">
-  <owner>izuzic@google.com</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    This histogram is recorded when the access loss warning dialog was shown to
-    the user. It logs the type of dialog shown. Android only.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordAccessLossWarningDialog{AccessLossWarningType}.UserAction"
-    enum="PasswordAccessLossWarningUserActions" expires_after="2026-01-18">
-  <owner>izuzic@google.com</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    This histogram logs the action that the user {AccessLossWarningType}
-    performed in the password access loss warning dialog. Recorded exactly when
-    the action takes place. Android only.
-  </summary>
-  <token key="AccessLossWarningType" variants="AccessLossWarningType"/>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordAccessLossWarningExportFlow.{AccessLossWarningType}.FinalStep"
-    enum="PasswordAccessLossWarningExportStep" expires_after="2025-11-16">
-  <owner>izuzic@google.com</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    This histogram logs the last export flow step that the user performed.
-    Recorded exactly when the export flow ends. Android only.
-  </summary>
-  <token key="AccessLossWarningType" variants="AccessLossWarningType"/>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordAccessLossWarningSheet.{AccessLossWarningType}.UserAction"
-    enum="PasswordAccessLossWarningUserActions" expires_after="2026-01-18">
-  <owner>izuzic@google.com</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    This histograms logs the action that the user performed in the password
-    access loss warning sheet. Recorded exactly when the action takes place.
-    Android only.
-  </summary>
-  <token key="AccessLossWarningType" variants="AccessLossWarningType"/>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordAccessLossWarningSheet{AccessLossWarningType}Trigger"
-    enum="PasswordAccessLossWarningTriggers" expires_after="2026-01-18">
-  <owner>izuzic@google.com</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    This histogram logs the UI surface that led to showing the password access
-    loss warning sheet for users {AccessLossWarningType}. Recorded when the
-    warning sheet is shown. Android only.
-  </summary>
-  <token key="AccessLossWarningType" variants="AccessLossWarningType"/>
-</histogram>
-
 <histogram name="PasswordManager.PasswordChange.ChangingFailedBubble"
     enum="PasswordManagerUIDismissalReason" expires_after="2025-11-30">
   <owner>atsvirchkova@google.com</owner>
@@ -3325,36 +3204,6 @@
   </token>
 </histogram>
 
-<histogram
-    name="PasswordManager.PasswordSettingsMigrationFailed.{Setting}.APIError2"
-    enum="PasswordStoreAndroidBackendAPIError" expires_after="2025-09-08">
-  <owner>sygiet@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    The error codes returned by the GMS Core Password preferences 1P API while
-    attempting to do migration for {Setting}. This is only recorded on Android.
-    Replaces
-    &quot;PasswordManager.PasswordSettingsMigrationFailed.{Setting}.APIError&quot;
-    which was overly recorded in rare cases if fetching a password setting fails
-    after the migration was just marked as done.
-  </summary>
-  <token key="Setting" variants="PasswordManagerSetting"/>
-</histogram>
-
-<histogram name="PasswordManager.PasswordSettingsMigrationSucceeded2"
-    enum="BooleanYesNo" expires_after="2025-09-22">
-  <owner>sygiet@google.com</owner>
-  <owner>vasilii@chromium.org</owner>
-  <summary>
-    The number of succesful password settings migration from Chrome to GMS.
-    Recorded for the local users on Android when migration finished because of a
-    success or failure along the way. Replaces
-    &quot;PasswordManager.PasswordSettingsMigrationSucceeded&quot; which was
-    overly recorded when the settings migration was being marked as done for
-    clients with default settings which weren't eligible for settings migration.
-  </summary>
-</histogram>
-
 <histogram name="PasswordManager.PasswordsGrouping.Time" units="ms"
     expires_after="2025-12-28">
   <owner>vsemeniuk@google.com</owner>
@@ -3435,21 +3284,6 @@
 </histogram>
 
 <histogram
-    name="PasswordManager.PasswordStore.WasEnrolledInUPMWhenBackendWasCreated"
-    enum="Boolean" expires_after="2026-01-04">
-  <owner>kazinova@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <owner>friedrichh@chromium.org</owner>
-  <summary>
-    Recorded on Android when the password store backend is created. This happens
-    on startup and once per profile. It logs whether the user is enrolled in
-    UPM. In this context, all profiles are enrolled unless they have encountered
-    an unrecoverable error upon querying GMS Core. Once that happens, a profile
-    pref is flipped and the client is considered unenrolled from that point on.
-  </summary>
-</histogram>
-
-<histogram
     name="PasswordManager.PasswordStoreAndroidBackend.Retry{Operation}.APIError"
     enum="PasswordStoreAndroidBackendAPIError" expires_after="2025-12-08">
   <owner>izuzic@google.com</owner>
@@ -3717,30 +3551,6 @@
   </token>
 </histogram>
 
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.PasswordRemovalStatus"
-    enum="BooleanSuccess" expires_after="2025-08-31">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    Records whether a call to remove all passwords in BuiltInBackend succeeded.
-    Recorded when the removal operation is finished.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.PasswordStoreProxyBackend.RemovedPasswordCount"
-    units="passwords" expires_after="2025-08-29">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    Records the number of credentials removed by
-    PasswordStoreProxyBackend::MaybeClearBuiltInBackend() when the deletion
-    actually took place. Recorded only when RemoveLoginsCreatedBetweenAsync()
-    operation was successful.
-  </summary>
-</histogram>
-
 <histogram name="PasswordManager.PasswordStore{Backend}.{Function}"
     enum="PasswordStoreAndroidBackendRequestStatus" expires_after="2026-01-18">
   <owner>maxan@chromium.org</owner>
@@ -4491,146 +4301,6 @@
   </summary>
 </histogram>
 
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.AddLoginCount"
-    units="passwords" expires_after="2025-08-22">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    Records the number of credentials successfully added to GMS Core during
-    MigrationForLocalUsers. Recorded when the migration is finished,
-    irrespective of the overall migration success.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.AndroidBackend.{MigrationOperation}.APIError"
-    enum="PasswordStoreAndroidBackendAPIError" expires_after="2025-11-09">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    Records the API error received when performing {MigrationOperation} on the
-    AndroidBacked as part of MigrationForLocalUsers. Reported immediately after
-    the operation finishes, unless it's a Get operation. For GetAllLogins, the
-    result is only reported after the replies come back fom both backends. Note
-    that the BuiltInBackend doesn't return API Errors so no similar histogram is
-    recorded for it.
-  </summary>
-  <token key="MigrationOperation" variants="MigrationOperation"/>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.Latency"
-    units="ms" expires_after="2025-10-12">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>friedrichh@chromium.org</owner>
-  <summary>
-    Real-time duration of MigrationForLocalUsers. Recorded when all operations
-    are completed and migration is finished.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.MergeWhereAndroidHasMostRecent"
-    units="passwords" expires_after="2025-08-22">
-  <owner>atsvirchkova@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    The number of conflicts found while migrating local passwords where the
-    credential already stored in GMS Core is kept instead of the one in Chrome.
-    A conflict is defined as both Chrome and GMS Core having credentials with
-    the same primary key, but different passwords. In that case the credential
-    that was updated or used last is considered to be the correct one.
-
-    Recorded when the entire migration finished successfully in order to avoid
-    double-counting.
-
-    The counterpart of this histogram, recording counts of conflicts where
-    Chrome had the more recent credential. is
-    &quot;PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.UpdateLoginCount&quot;
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.MigratedLoginsTotalCount"
-    units="passwords" expires_after="2025-08-22">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    Records the number of credential successfully migrated to GMS Core during
-    MigrationForLocalUsers. Recorded when the migration is finished. If the
-    migration fails in the middle after writting only part of credentials to GMS
-    core, the metric will report only those that were actually written before
-    the failure.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.ProgressState"
-    enum="LocalPwdMigrationProgressState" expires_after="2025-10-26">
-  <owner>atsvirchkova@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    Recorded when the local passwords migration is scheduled, when it's started
-    and when it finishes, irrespective of success status.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.Success"
-    enum="BooleanSuccess" expires_after="2025-10-12">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>friedrichh@chromium.org</owner>
-  <summary>
-    Records success of MigrationForLocalUsers. Recorded when the migration is
-    finished.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.UpdateLoginCount"
-    units="passwords" expires_after="2025-08-22">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <owner>atsvirchkova@google.com</owner>
-  <summary>
-    Records the number of credentials successfully updated in GMS Core during
-    MigrationForLocalUsers. Recorded when the migration is finished,
-    irrespective of the overall migration success.
-  </summary>
-</histogram>
-
-<histogram
-    name="PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers.{BackendType}.{MigrationOperation}.Success"
-    enum="BooleanSuccess" expires_after="2025-12-28">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>ioanap@chromium.org</owner>
-  <summary>
-    Records whether performing {MigrationOperation} on the {BackendType} as part
-    of MigrationForLocalUsers succeeded or not. Reported immediately after the
-    operation finishes, unless it's a Get operation. For GetAllLogins, the
-    result is only reported after the replies come back fom both backends.
-  </summary>
-  <token key="BackendType">
-    <variant name="AndroidBackend"/>
-    <variant name="BuiltInBackend"/>
-  </token>
-  <token key="MigrationOperation" variants="MigrationOperation"/>
-</histogram>
-
-<histogram name="PasswordManager.UnifiedPasswordManager.WasMigrationDone"
-    enum="BooleanSuccess" expires_after="2025-10-26">
-  <owner>vsemeniuk@google.com</owner>
-  <owner>friedrichh@chromium.org</owner>
-  <summary>
-    Records whether passwords were successfully migrated from built in backed to
-    android backed and the current migration version stored in pref is
-    greater/equal to the version from feature parameters. Recorded on start up.
-  </summary>
-</histogram>
-
 <histogram name="PasswordManager.UpdateUIDismissalReason"
     enum="PasswordManagerUIDismissalReason" expires_after="2025-12-07">
   <owner>vasilii@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml
index 08f7f18..b833d0a 100644
--- a/tools/metrics/histograms/metadata/profile/histograms.xml
+++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -599,7 +599,8 @@
 
 <histogram name="Profile.PercentageOfManagedProfiles" units="units"
     expires_after="2025-12-07">
-  <owner>agawronska@chromium.org</owner>
+  <owner>longbowei@google.com</owner>
+  <owner>zhangwenyu@google.com</owner>
   <owner>cros-families-eng@google.com</owner>
   <summary>
     Tracks the percentage (0-100) of profiles that are locally managed. Only
diff --git a/tools/metrics/histograms/metadata/startup/histograms.xml b/tools/metrics/histograms/metadata/startup/histograms.xml
index 454eb62f..43851b3be 100644
--- a/tools/metrics/histograms/metadata/startup/histograms.xml
+++ b/tools/metrics/histograms/metadata/startup/histograms.xml
@@ -1144,7 +1144,7 @@
 <histogram name="Startup.ShowDefaultPromoFromApps"
     enum="MobileSessionCallerApp" expires_after="2023-05-23">
   <owner>olivierrobin@chromium.org</owner>
-  <owner>bling-get-set-up@google.com</owner>
+  <owner>bling-pandamonium@google.com</owner>
   <summary>
     The external application requesting showing the default browser settings.
     Logged when the command is received from the external application. Histogram
diff --git a/tools/metrics/histograms/metadata/tab/enums.xml b/tools/metrics/histograms/metadata/tab/enums.xml
index ae19741..bd5db1fb 100644
--- a/tools/metrics/histograms/metadata/tab/enums.xml
+++ b/tools/metrics/histograms/metadata/tab/enums.xml
@@ -285,6 +285,20 @@
   <int value="2" label="Selector"/>
 </enum>
 
+<!-- LINT.IfChange(TabGroupingTransitionType) -->
+
+<enum name="TabGroupingTransitionType">
+  <int value="-1" label="Invalid type"/>
+  <int value="0" label="Tab started ungrouped and ended ungrouped"/>
+  <int value="1" label="Tab started ungrouped and ended grouped"/>
+  <int value="2" label="Tab started grouped and ended ungrouped"/>
+  <int value="3" label="Tab started grouped and ended in the same group"/>
+  <int value="4"
+      label="Tab started grouped and ended outside of the same group"/>
+</enum>
+
+<!-- LINT.ThenChange(//chrome/browser/ui/tabs/tab_creation_metrics_controller.h:TabGroupingTransitionType) -->
+
 <!-- LINT.IfChange(TabGroupLoadedEmptiness)-->
 
 <enum name="TabGroupLoadedEmptiness">
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index 607e620..5e662152 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -376,6 +376,17 @@
   </token>
 </histogram>
 
+<histogram name="Tab.GroupingTransition" enum="TabGroupingTransitionType"
+    expires_after="2026-06-11">
+  <owner>temao@chromium.org</owner>
+  <owner>dpenning@chromium.org</owner>
+  <owner>top-chrome-desktop-ui@google.com</owner>
+  <summary>
+    [Desktop] Records different types of tab grouping transition states 10
+    seconds after a tab is created.
+  </summary>
+</histogram>
+
 <histogram name="Tab.HasCustomUnderPageBackgroundColor" enum="BooleanPresent"
     expires_after="2025-11-29">
   <owner>gambard@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/user_education/histograms.xml b/tools/metrics/histograms/metadata/user_education/histograms.xml
index f91ac9a..1e3788d 100644
--- a/tools/metrics/histograms/metadata/user_education/histograms.xml
+++ b/tools/metrics/histograms/metadata/user_education/histograms.xml
@@ -33,6 +33,8 @@
                saved state to resume.."/>
   <variant name="ComposeProactiveNudge"
       summary="For Compose feature; shown on autofill popup."/>
+  <variant name="DevToolsAiAssistanceFileAgent"
+      summary="Promotion forDevTools AI Assistance File Agent."/>
   <variant name="Glic" summary="Glic toggle on settings page."/>
   <variant name="GlicAppMenuNewBadge"
       summary="Glic menu item in the three dot menu."/>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 8b76d17e..f33588f 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/361808c959b026d558c9948602ea38bf25d8981e/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "dd6b784b32857ecf19d587b25cf2ff62075aebbe",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/edd70a17a1fdc811de00869e4e6aa6cbef92b58f/trace_processor_shell.exe"
+            "hash": "206c9dc02f9695bd203a5d3510ae116b9717a5c5",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/dc3cfc940d5a6335eadbf440b51560725a9ab7e2/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "ab1a0d9236a63649044414663b6ace711253648f",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v51.2/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "4031642a44868b720ca42d76c7090358ebc77a2c",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/edd70a17a1fdc811de00869e4e6aa6cbef92b58f/trace_processor_shell"
+            "hash": "fe34974f2e4653b9a611cab074ec05fe84f64158",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/dc3cfc940d5a6335eadbf440b51560725a9ab7e2/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/rust/build_rust.py b/tools/rust/build_rust.py
index c2e22d12..dbad3c5 100755
--- a/tools/rust/build_rust.py
+++ b/tools/rust/build_rust.py
@@ -66,9 +66,9 @@
 
 EXCLUDED_TESTS = [
     # Temporarily disabled due to https://crbug.com/396424971
-    os.path.join('tests', 'codegen', 'common_prim_int_ptr.rs'),
+    os.path.join('tests', 'codegen-llvm', 'common_prim_int_ptr.rs'),
     # Temporarily disabled due to https://crbug.com/433249564
-    os.path.join('tests', 'codegen', 'enum', 'enum-discriminant-eq.rs'),
+    os.path.join('tests', 'codegen-llvm', 'enum', 'enum-discriminant-eq.rs'),
 ]
 EXCLUDED_TESTS_WINDOWS = [
     # Temporarily disabled due to https://crbug.com/379308086
@@ -143,7 +143,7 @@
 # Which test suites to run. Any failure will fail the build.
 TEST_SUITES = [
     'library/std',
-    'tests/codegen',
+    'tests/codegen-llvm',
     'tests/ui',
 ]
 
diff --git a/tools/test_selection/decisiongraph_invoker.py b/tools/test_selection/decisiongraph_invoker.py
index 380586e..7e7feeb 100755
--- a/tools/test_selection/decisiongraph_invoker.py
+++ b/tools/test_selection/decisiongraph_invoker.py
@@ -4,15 +4,38 @@
 # found in the LICENSE file.
 
 import argparse
+import os
 import pprint
 import requests
 import sys
 import json
 
+from enum import Enum
+
+
+class TestSelectionPhase(Enum):
+  # Trigger represents the first phase when ML model is triggered with the
+  # required context to generate tests' pass probability.
+  TRIGGER = 1
+  # Fetch represents the second phase when results generated by ML model are
+  # fetched and used for test selection, based on a predetermined pass
+  # probability.
+  FETCH = 2
+
+
 API_URL = 'https://decisiongraph-pa.googleapis.com/v1/rundecisiongraph'
-DECISION_GRAPH_NAME = 'smart_test_selection_graph_chrome'
-STAGE_ID = 'test_selection_for_%d_%d_%d'
-STAGE_NAME = 'smart_test_selection_stage'
+DECISION_GRAPH_NAME = {
+    TestSelectionPhase.TRIGGER: 'sts_chrome_trigger_model_root',
+    TestSelectionPhase.FETCH: 'sts_chrome_fetch_results_root'
+}
+STAGE_ID = {
+    TestSelectionPhase.TRIGGER: 'trigger_model_for_%d_%d_%d',
+    TestSelectionPhase.FETCH: 'fetch_results_for_%d_%d_%d'
+}
+STAGE_NAME = {
+    TestSelectionPhase.TRIGGER: 'sts_chrome_trigger_model',
+    TestSelectionPhase.FETCH: 'sts_chrome_fetch_results'
+}
 PROJECT = 'chromium/src'
 BRANCH = 'main'
 # Only the first word of gerrit host, i.e., %s-review.googlesource.com
@@ -44,12 +67,11 @@
     response = requests.post(url, json=json_payload, timeout=TIMEOUT_SECONDS)
     print(response.text)
     print(response.status_code)
-    print(response.json)
     response.raise_for_status(
-    )  # Raise an HTTPError for bad responses (4xx and 5xx).
+    )  # Raise an HTTPError for bad responses (4xx and 5xx)
     return response.json()
   except requests.exceptions.RequestException as e:
-    print(f"An error occurred: {e}")
+    print(f'An error occurred: {e}')
     return None
 
 
@@ -64,82 +86,132 @@
     """
   config_data = {}
   try:
-    with open(file_path, "r", encoding="utf-8") as f:
+    with open(file_path, 'r', encoding='utf-8') as f:
       config_data = json.load(f)
   except FileNotFoundError:
-    print(f"Error: Configuration file not found at {file_path}")
+    print(f'Error: Configuration file not found at {file_path}')
     sys.exit(1)
   except json.JSONDecodeError as e:
-    print(f"Error: Could not decode JSON from {file_path}. Details: {e}")
+    print(f'Error: Could not decode JSON from {file_path}. Details: {e}')
     sys.exit(1)
   except Exception as e:
     print(
-        f"Unexpected error occurred while reading the configuration file: {e}")
+        f'Unexpected error occurred while reading the configuration file: {e}')
     sys.exit(1)
 
   # Validate required arguments needed to make API call.
-  required_args = ["build_id", "change", "patchset", "builder", "api_key"]
+  required_args = ['build_id', 'change', 'patchset', 'builder', 'api_key']
   missing_args = [arg for arg in required_args if arg not in config_data]
 
   if missing_args:
-    print(f"Error: Missing required arguments in JSON config file.")
+    print('Error: Missing required arguments in JSON config file.')
     for arg in missing_args:
-      print(f"  - {arg}")
+      print(f'  - {arg}')
     sys.exit(1)
 
   # Type checking/conversion for API call parameters.
   try:
-    config_data["change"] = int(config_data["change"])
-    config_data["patchset"] = int(config_data["patchset"])
-    if not isinstance(config_data["build_id"], str):
+    config_data['change'] = int(config_data['change'])
+    config_data['patchset'] = int(config_data['patchset'])
+    if not isinstance(config_data['build_id'], str):
       print("Error: 'build_id' must be a string in the JSON configuration.")
       sys.exit(1)
-    if not isinstance(config_data["builder"], str):
+    if not isinstance(config_data['builder'], str):
       print("Error: 'builder' must be a string in the JSON configuration.")
       sys.exit(1)
-    if not isinstance(config_data["api_key"], str):
-      print("Error: 'api_key_file' must be a string in the JSON configuration.")
+    if not isinstance(config_data['api_key'], str):
+      print("Error: 'api_key' must be a string in the JSON configuration.")
       sys.exit(1)
 
   except ValueError:
-    print(f"Error: Invalid data type for 'change' or 'patchset' in JSON. " +
+    print("Error: Invalid data type for 'change' or 'patchset' in JSON. "
           "Expected integers.")
     sys.exit(1)
   except KeyError as e:
     # This should be caught by missing_args check, but it's included
     # as a safeguard.
-    print(f"Error: A required key {e} is missing during type validation.")
+    print(f'Error: A required key {e} is missing during type validation.')
     sys.exit(1)
 
   return config_data
 
 
+def overwrite_filter_file(filter_file_dir, test_suite, tests_to_skip):
+  """
+  Overwrites a filter file with tests to skip.
+
+  Args:
+    filter_file_dir: The directory containing the filter files.
+    test_suite: The name of the test suite (e.g., 'browser_tests').
+    tests_to_skip: A list of test names to be written to the file.
+  """
+  file_name = f'{test_suite}.filter'
+  file_path = os.path.join(filter_file_dir, file_name)
+
+  # The calling script is responsible for creating the directory.
+  if not os.path.isdir(filter_file_dir):
+    print(f'Error: Filter file directory not found at {filter_file_dir}')
+    return False
+
+  try:
+    # Overwrite the file with the new list of tests to skip.
+    with open(file_path, 'w', encoding='utf-8') as f:
+      if tests_to_skip:
+        f.write(
+            '# A list of tests to be skipped, generated by test selection.\n')
+        for test_name in tests_to_skip:
+          f.write(f'-{test_name}\n')
+    print(
+        f'Successfully wrote {len(tests_to_skip)} tests to skip to {file_path}')
+    return True
+  except Exception as e:
+    print(f'An error occurred while writing to {file_path}: {e}')
+    return False
+
+
 def main():
   parser = argparse.ArgumentParser(
       description=
-      "Fetch data from an API using parameters from a JSON config file.")
-  parser.add_argument("--test-targets",
+      'A script to trigger or fetch results for Smart Test Selection.')
+  parser.add_argument('--test-targets',
                       required=True,
                       nargs='+',
                       type=str,
-                      help="Name of the test targets e.g., browser_tests.")
+                      help='Name of the test targets e.g., browser_tests.')
   parser.add_argument(
-      "--sts-config-file",
+      '--sts-config-file',
       required=True,
       type=str,
-      help="Path to the JSON file containing config for smart test selection.")
+      help='Path to the JSON file containing config for smart test selection.')
+  parser.add_argument(
+      '--test-selection-phase',
+      required=True,
+      type=str.upper,
+      choices=[p.name for p in TestSelectionPhase],
+      help='The phase of test selection to run: TRIGGER or FETCH.')
+  parser.add_argument(
+      '--filter-file-dir',
+      type=str,
+      help='Directory to write test filter files. Required for FETCH phase.')
   args = parser.parse_args()
 
+  # Set the phase based on the command-line flag.
+  phase = TestSelectionPhase[args.test_selection_phase]
+
+  # --filter-file-dir is only needed for the FETCH phase.
+  if phase == TestSelectionPhase.FETCH and not args.filter_file_dir:
+    parser.error('--filter-file-dir is required when phase is FETCH.')
+
   config = load_config_from_json(args.sts_config_file)
 
-  build_id = config["build_id"]
-  change = config["change"]
-  patchset = config["patchset"]
-  builder = config["builder"]
-  api_key = config["api_key"]
+  build_id = config['build_id']
+  change = config['change']
+  patchset = config['patchset']
+  builder = config['builder']
+  api_key = config['api_key']
 
   # Find the corresponding "main" CQ builder name.
-  canonical_builder = builder.removesuffix("-test-selection")
+  canonical_builder = builder.removesuffix('-test-selection')
 
   test_target_batches = [
       args.test_targets[i:i + BATCH_SIZE]
@@ -149,7 +221,7 @@
   return_status = 0
   for batch_idx, test_target_batch in enumerate(test_target_batches):
     checks = []
-    print("batch num = %d" % batch_idx)
+    print('batch num = %d' % batch_idx)
     for test_target in test_target_batch:
       check = {
           'identifier': {
@@ -168,19 +240,20 @@
       }
       checks.append(check)
 
+    stage_id = STAGE_ID[phase] % (change, patchset, batch_idx)
     payload = {
         'graph': {
             'name':
-            DECISION_GRAPH_NAME,
+            DECISION_GRAPH_NAME[phase],
             'stages': [{
                 'stage': {
-                    'id': STAGE_ID % (change, patchset, batch_idx),
-                    'name': STAGE_NAME,
+                    'id': stage_id,
+                    'name': STAGE_NAME[phase],
                 },
                 'execution_options': {
                     'location': LOCATION_ENUM,
                     'address': STAGE_SERVICE_GSLB,
-                    'prepare': True,
+                    'prepare': phase == TestSelectionPhase.TRIGGER,
                     'max_duration': {
                         'seconds': MAX_DURATION_SECONDS
                     },
@@ -191,8 +264,8 @@
         },
         'input': [{
             'stage': {
-                'id': STAGE_ID % (change, patchset, batch_idx),
-                'name': STAGE_NAME,
+                'id': stage_id,
+                'name': STAGE_NAME[phase],
             },
             'input': [{
                 'checks': checks,
@@ -206,17 +279,41 @@
             },
         }]
     }
-    print("payload = ")
+    print('payload = ')
     pprint.pprint(payload)
 
     request_with_key = '%s?key=%s' % (API_URL, api_key)
     response_data = fetch_api_data(url=request_with_key, json_payload=payload)
 
     if response_data:
-      print("API Response:")
-      print(response_data)
+      if phase == TestSelectionPhase.TRIGGER:
+        print('API Response:')
+        pprint.pprint(response_data)
+      else:  # FETCH phase
+        try:
+          stage_outputs = response_data['outputs']
+          assert len(stage_outputs) == 1
+          checks = stage_outputs[0]['checks']
+          for count, check in enumerate(checks):
+            print(f'processing check {count}')
+            if 'children' not in check:
+              continue
+
+            children = check['children']
+            test_suite = check['identifier']['luciTest']['testSuite']
+            tests_to_skip = []
+            for child in children:
+              tests_to_skip.append(child['identifier']['luciTest']['testId'])
+
+            if not overwrite_filter_file(args.filter_file_dir, test_suite,
+                                         tests_to_skip):
+              return_status = 1
+        except (KeyError, IndexError) as e:
+          print('Error when parsing response from decisiongraph api')
+          pprint.pprint(response_data)
+          raise e
     else:
-      print("Failed to fetch data from the API.")
+      print('Failed to fetch data from the API.')
       return_status = 1
 
   sys.exit(return_status)
diff --git a/tools/test_selection/decisiongraph_invoker_test.py b/tools/test_selection/decisiongraph_invoker_test.py
index fbcc74e..b0b03f4 100755
--- a/tools/test_selection/decisiongraph_invoker_test.py
+++ b/tools/test_selection/decisiongraph_invoker_test.py
@@ -7,9 +7,12 @@
 import json
 import sys
 import os
+import tempfile
+import shutil
 from unittest.mock import patch, MagicMock
 
 # We need to adjust the path to import the script directly.
+# This assumes the test script is in the same directory as the main script.
 sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
 
 import decisiongraph_invoker as dgi
@@ -19,23 +22,24 @@
 class TestDecisionGraphInvoker(unittest.TestCase):
 
   def setUp(self):
+    self.maxDiff = None
+    self.test_dir = tempfile.mkdtemp()
     self.config_data = {
-        "build_id": "12345",
-        "change": 123456,
-        "patchset": 1,
-        "builder": "chromium-commit-queue",
-        "api_key": "test_api_key_123"
+        'build_id': '12345',
+        'change': 123456,
+        'patchset': 1,
+        'builder': 'chromium-commit-queue',
+        'api_key': 'test_api_key_123'
     }
-    self.config_file_path = "test_config.json"
+    self.config_file_path = os.path.join(self.test_dir, 'test_config.json')
     self.api_url_with_key = f"{dgi.API_URL}?key={self.config_data['api_key']}"
 
   def tearDown(self):
-    if os.path.exists(self.config_file_path):
-      os.remove(self.config_file_path)
+    shutil.rmtree(self.test_dir)
 
   def _create_mock_config_file(self, data):
     """Helper to create a mock JSON config file."""
-    with open(self.config_file_path, "w", encoding="utf-8") as f:
+    with open(self.config_file_path, 'w', encoding='utf-8') as f:
       json.dump(data, f)
 
   @patch('builtins.print')
@@ -47,31 +51,31 @@
   @patch('sys.exit')
   @patch('builtins.print')
   def test_load_config_from_json_file_not_found(self, mock_print, mock_exit):
-    dgi.load_config_from_json("non_existent_file.json")
+    dgi.load_config_from_json('non_existent_file.json')
     mock_print.assert_any_call(
-        "Error: Configuration file not found at non_existent_file.json")
+        'Error: Configuration file not found at non_existent_file.json')
     mock_exit.assert_called_with(1)
 
   @patch('sys.exit')
   @patch('builtins.print')
   def test_load_config_from_json_missing_args(self, mock_print, mock_exit):
-    incomplete_config = {"build_id": "123", "change": 1}
+    incomplete_config = {'build_id': '123', 'change': 1}
     self._create_mock_config_file(incomplete_config)
     dgi.load_config_from_json(self.config_file_path)
     mock_print.assert_any_call(
-        f"Error: Missing required arguments in JSON config file.")
+        'Error: Missing required arguments in JSON config file.')
     mock_exit.assert_called_with(1)
 
   @patch('sys.exit')
   @patch('builtins.print')
   def test_load_config_from_json_invalid_type(self, mock_print, mock_exit):
     invalid_config = self.config_data.copy()
-    invalid_config["change"] = "not_an_int"
+    invalid_config['change'] = 'not_an_int'
     self._create_mock_config_file(invalid_config)
     dgi.load_config_from_json(self.config_file_path)
     mock_print.assert_any_call(
-        "Error: Invalid data type for 'change' or 'patchset' in JSON."
-        " Expected integers.")
+        "Error: Invalid data type for 'change' or 'patchset' in JSON. "
+        "Expected integers.")
     mock_exit.assert_called_with(1)
 
   @patch('builtins.print')
@@ -79,124 +83,181 @@
   def test_fetch_api_data_success(self, mock_post, mock_print):
     mock_response = MagicMock()
     mock_response.status_code = 200
-    mock_response.json.return_value = {"status": "success"}
+    mock_response.json.return_value = {'status': 'success'}
     mock_response.text = '{"status": "success"}'
     mock_response.raise_for_status.return_value = None
 
     mock_post.return_value = mock_response
 
     response = dgi.fetch_api_data(self.api_url_with_key, {})
-    self.assertEqual(response, {"status": "success"})
+    self.assertEqual(response, {'status': 'success'})
     mock_print.assert_any_call('{"status": "success"}')
     mock_print.assert_any_call(200)
 
   @patch('builtins.print')
   @patch('requests.post')
   def test_fetch_api_data_failure_http_error(self, mock_post, mock_print):
-    # Create a mock response object for HTTPError.
     mock_response = MagicMock()
     mock_response.status_code = 500
-    mock_response.text = "Internal Server Error"
+    mock_response.text = 'Internal Server Error'
     mock_response.raise_for_status.side_effect = (
-        requests.exceptions.HTTPError("500 Server Error"))
+        requests.exceptions.HTTPError('500 Server Error'))
 
     mock_post.return_value = mock_response
 
     response = dgi.fetch_api_data(self.api_url_with_key, {})
     self.assertIsNone(response)
-    mock_print.assert_any_call(f"An error occurred: 500 Server Error")
-    mock_print.assert_any_call("Internal Server Error")
+    mock_print.assert_any_call('An error occurred: 500 Server Error')
+    mock_print.assert_any_call('Internal Server Error')
     mock_print.assert_any_call(500)
 
-  @patch('builtins.print')
-  @patch('requests.post')
-  def test_fetch_api_data_failure_request_exception(self, mock_post,
-                                                    mock_print):
-    # Simulate a network error (e.g., timeout, connection refused).
-    mock_post.side_effect = requests.exceptions.ConnectionError(
-        "Max retries exceeded")
+  def test_overwrite_filter_file_success(self):
+    test_suite = 'browser_tests'
+    tests_to_skip = ['Test1.testA', 'Test2.testB']
+    result = dgi.overwrite_filter_file(self.test_dir, test_suite, tests_to_skip)
+    self.assertTrue(result)
+    filter_file_path = os.path.join(self.test_dir, f'{test_suite}.filter')
+    self.assertTrue(os.path.exists(filter_file_path))
+    with open(filter_file_path, 'r', encoding='utf-8') as f:
+      content = f.read()
+      self.assertIn('-Test1.testA', content)
+      self.assertIn('-Test2.testB', content)
 
-    response = dgi.fetch_api_data(self.api_url_with_key, {})
-    self.assertIsNone(response)
-    mock_print.assert_called_with("An error occurred: Max retries exceeded")
+  @patch('builtins.print')
+  def test_overwrite_filter_file_dir_not_found(self, mock_print):
+    result = dgi.overwrite_filter_file('non_existent_dir', 'suite', [])
+    self.assertFalse(result)
+    mock_print.assert_called_with(
+        'Error: Filter file directory not found at non_existent_dir')
 
   @patch('sys.exit')
   @patch('decisiongraph_invoker.load_config_from_json')
   @patch('decisiongraph_invoker.fetch_api_data')
-  @patch('builtins.print')
-  def test_main_single_batch_success(self, mock_print, mock_fetch_api_data,
-                                     mock_load_config_from_json, mock_exit):
-    mock_load_config_from_json.return_value = self.config_data
-    mock_fetch_api_data.return_value = {"output": [{"result": "success"}]}
+  def test_main_trigger_phase_success(self, mock_fetch, mock_load_config,
+                                      mock_exit):
+    mock_load_config.return_value = self.config_data
+    mock_fetch.return_value = {'output': [{'result': 'success'}]}
 
     with patch('sys.argv', [
         'decisiongraph_invoker.py', '--test-targets', 'browser_tests',
-        'unit_tests', '--sts-config-file', self.config_file_path
+        '--sts-config-file', self.config_file_path, '--test-selection-phase',
+        'TRIGGER'
     ]):
       dgi.main()
-      mock_fetch_api_data.assert_called_once()
-      mock_exit.assert_called_with(0)
-
-  @patch('sys.exit')
-  @patch('decisiongraph_invoker.load_config_from_json')
-  @patch('decisiongraph_invoker.fetch_api_data')
-  @patch('builtins.print')
-  def test_main_multiple_batches_success(self, mock_print, mock_fetch_api_data,
-                                         mock_load_config_from_json, mock_exit):
-    mock_load_config_from_json.return_value = self.config_data
-    mock_fetch_api_data.return_value = {"output": [{"result": "success"}]}
-
-    # Simulate command-line arguments for multiple batches.
-    test_targets = [f"test_{i}" for i in range(dgi.BATCH_SIZE + 2)]  # 2 batches
-    with patch('sys.argv', ['decisiongraph_invoker.py', '--test-targets'] +
-               test_targets + ['--sts-config-file', self.config_file_path]):
-      dgi.main()
-      self.assertEqual(mock_fetch_api_data.call_count, 2)  # Expect 2 calls
-      mock_exit.assert_called_with(0)
-
-  @patch('sys.exit')
-  @patch('decisiongraph_invoker.load_config_from_json')
-  @patch('decisiongraph_invoker.fetch_api_data')
-  @patch('builtins.print')
-  def test_main_api_failure(self, mock_print, mock_fetch_api_data,
-                            mock_load_config_from_json, mock_exit):
-    mock_load_config_from_json.return_value = self.config_data
-    mock_fetch_api_data.return_value = None  # Simulate API failure.
-
-    with patch('sys.argv', [
-        'decisiongraph_invoker.py', '--test-targets', 'browser_tests',
-        '--sts-config-file', self.config_file_path
-    ]):
-      dgi.main()
-      mock_fetch_api_data.assert_called_once()
-      mock_print.assert_any_call("Failed to fetch data from the API.")
-      mock_exit.assert_called_with(1)
-
-  @patch('sys.exit')
-  @patch('decisiongraph_invoker.load_config_from_json')
-  @patch('decisiongraph_invoker.fetch_api_data')
-  @patch('builtins.print')
-  def test_main_canonical_builder_conversion(self, mock_print,
-                                             mock_fetch_api_data,
-                                             mock_load_config_from_json,
-                                             mock_exit):
-    config_with_suffix = self.config_data.copy()
-    config_with_suffix["builder"] = "linux-test-selection"
-    mock_load_config_from_json.return_value = config_with_suffix
-    mock_fetch_api_data.return_value = {"output": [{"result": "success"}]}
-
-    with patch('sys.argv', [
-        'decisiongraph_invoker.py', '--test-targets', 'browser_tests',
-        '--sts-config-file', self.config_file_path
-    ]):
-      dgi.main()
-      _, kwargs = mock_fetch_api_data.call_args
+      mock_fetch.assert_called_once()
+      _, kwargs = mock_fetch.call_args
       payload = kwargs['json_payload']
-      self.assertEqual(
-          payload['input'][0]['input'][0]['checks'][0]['identifier']
-          ['luci_test']['builder'], "linux")
+      self.assertTrue(
+          payload['graph']['stages'][0]['execution_options']['prepare'])
       mock_exit.assert_called_with(0)
 
+  @patch('sys.exit')
+  @patch('decisiongraph_invoker.load_config_from_json')
+  @patch('decisiongraph_invoker.fetch_api_data')
+  def test_main_fetch_phase_success(self, mock_fetch, mock_load_config,
+                                    mock_exit):
+    mock_load_config.return_value = self.config_data
+    mock_fetch.return_value = {
+        'outputs': [{
+            'checks': [{
+                'identifier': {
+                    'luciTest': {
+                        'testSuite': 'browser_tests'
+                    }
+                },
+                'children': [{
+                    'identifier': {
+                        'luciTest': {
+                            'testId': 'TestClass.testExample1'
+                        }
+                    }
+                }, {
+                    'identifier': {
+                        'luciTest': {
+                            'testId': 'TestClass.testExample2'
+                        }
+                    }
+                }]
+            }]
+        }]
+    }
+
+    with patch('sys.argv', [
+        'decisiongraph_invoker.py', '--test-targets', 'browser_tests',
+        '--sts-config-file', self.config_file_path, '--test-selection-phase',
+        'FETCH', '--filter-file-dir', self.test_dir
+    ]):
+      dgi.main()
+
+      mock_fetch.assert_called_once()
+      _, kwargs = mock_fetch.call_args
+      payload = kwargs['json_payload']
+      self.assertFalse(
+          payload['graph']['stages'][0]['execution_options']['prepare'])
+
+      filter_file_path = os.path.join(self.test_dir, 'browser_tests.filter')
+      self.assertTrue(os.path.exists(filter_file_path))
+      with open(filter_file_path, 'r', encoding='utf-8') as f:
+        content = f.read()
+        self.assertIn('-TestClass.testExample1', content)
+        self.assertIn('-TestClass.testExample2', content)
+
+      mock_exit.assert_called_with(0)
+
+  @patch('sys.exit')
+  @patch('decisiongraph_invoker.load_config_from_json')
+  @patch('decisiongraph_invoker.fetch_api_data')
+  def test_main_fetch_phase_key_error(self, mock_fetch, mock_load_config,
+                                      mock_exit):
+    mock_load_config.return_value = self.config_data
+    # Malformed response missing 'testId'
+    mock_fetch.return_value = {
+        'outputs': [{
+            'checks': [{
+                'identifier': {
+                    'luciTest': {
+                        'testSuite': 'browser_tests'
+                    }
+                },
+                'children': [{
+                    'identifier': {
+                        'luciTest': {}
+                    }
+                }]
+            }]
+        }]
+    }
+
+    with patch('sys.argv', [
+        'decisiongraph_invoker.py', '--test-targets', 'browser_tests',
+        '--sts-config-file', self.config_file_path, '--test-selection-phase',
+        'FETCH', '--filter-file-dir', self.test_dir
+    ]):
+      with self.assertRaises(KeyError):
+        dgi.main()
+
+  @patch('argparse.ArgumentParser.error')
+  def test_main_fetch_phase_missing_dir_arg(self, mock_parser_error):
+    # Make the mock raise an exception to halt execution, which is what
+    # parser.error() does internally by calling sys.exit().
+    mock_parser_error.side_effect = SystemExit
+
+    with self.assertRaises(SystemExit):
+      with patch('sys.argv', [
+          'decisiongraph_invoker.py',
+          '--test-targets',
+          'browser_tests',
+          '--sts-config-file',
+          self.config_file_path,
+          '--test-selection-phase',
+          'FETCH',
+      ]):
+        dgi.main()
+
+    # Verify that parser.error was called with the correct message.
+    mock_parser_error.assert_called_with(
+        '--filter-file-dir is required when phase is FETCH.')
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/ui/accessibility/ax_bitset.h b/ui/accessibility/ax_bitset.h
index f00c689..3149d45 100644
--- a/ui/accessibility/ax_bitset.h
+++ b/ui/accessibility/ax_bitset.h
@@ -15,23 +15,25 @@
 namespace ui {
 
 // A helper class to store AX-related boolean enums.
-// IMPORTANT: This AXBitset implementation uses single uint64_t bitmasks and is
+// IMPORTANT: This AXBitset implementation uses single uint32_t bitmasks and is
 // therefore limited to managing enums whose underlying integer values are
-// strictly less than 64 (i.e., in the range [0, 63]). Enum values outside
+// strictly less than 32 (i.e., in the range [0, 31]). Enum values outside
 // this range will lead to incorrect behavior or will be ignored.
 template <typename T>
 class AXBitset {
  public:
   AXBitset() = default;
+  AXBitset(uint32_t initial_set_bits, uint32_t initial_values)
+      : set_bits_(initial_set_bits), values_(initial_values) {}
   ~AXBitset() = default;
 
-  uint64_t GetSetBits() const { return set_bits_; }
-  uint64_t GetValues() const { return values_; }
+  uint32_t GetSetBits() const { return set_bits_; }
+  uint32_t GetValues() const { return values_; }
 
   // Returns whether enum T at |value| is set to true, false or unset.
-  std::optional<bool> Has(T enum_value) const {
-    uint64_t index = static_cast<uint64_t>(enum_value);
-    uint64_t mask = 1ULL << index;
+  std::optional<bool> Get(T enum_value) const {
+    uint32_t index = static_cast<uint32_t>(enum_value);
+    uint32_t mask = 1ULL << index;
     // Check if the value is set.
     if (set_bits_ & mask) {
       return values_ & mask;
@@ -41,8 +43,8 @@
 
   // Sets the enum T at |enum_value| to true or false.
   void Set(T enum_value, bool bool_value) {
-    uint64_t index = static_cast<uint64_t>(enum_value);
-    uint64_t mask = 1ULL << index;
+    uint32_t index = static_cast<uint32_t>(enum_value);
+    uint32_t mask = 1ULL << index;
     // Mark as set.
     set_bits_ |= mask;
     if (bool_value) {
@@ -55,8 +57,8 @@
   }
 
   void Unset(T enum_value) {
-    uint64_t index = static_cast<uint64_t>(enum_value);
-    uint64_t mask = 1ULL << index;
+    uint32_t index = static_cast<uint32_t>(enum_value);
+    uint32_t mask = 1ULL << index;
     // Mark as not set.
     set_bits_ &= ~mask;
   }
@@ -69,17 +71,17 @@
   // attributes.
   void ForEach(
       base::FunctionRef<void(T attribute, bool value)> function) const {
-    uint64_t remainder = set_bits_;
+    uint32_t remainder = set_bits_;
 
     while (remainder) {
-      // Find the index (0-63) of the least significant bit that is set to 1
+      // Find the index (0-31) of the least significant bit that is set to 1
       // in 'remainder'. This corresponds to the enum's integer value.
       // std::countr_zero counts trailing zeros; e.g., for 0b...1000, it
       // returns 3.
       int index = std::countr_zero(remainder);
 
       T attribute = static_cast<T>(index);
-      uint64_t mask = 1ULL << index;
+      uint32_t mask = 1ULL << index;
       bool attribute_value = static_cast<bool>(values_ & mask);
 
       function(attribute, attribute_value);
@@ -116,8 +118,8 @@
   friend bool operator==(const AXBitset<U>& lhs, const AXBitset<U>& rhs);
 
  private:
-  uint64_t set_bits_ = 0;
-  uint64_t values_ = 0;
+  uint32_t set_bits_ = 0;
+  uint32_t values_ = 0;
 };
 
 template <typename T>
diff --git a/ui/accessibility/ax_bitset_unittest.cc b/ui/accessibility/ax_bitset_unittest.cc
index d6a3fba9..f9ea21c3a 100644
--- a/ui/accessibility/ax_bitset_unittest.cc
+++ b/ui/accessibility/ax_bitset_unittest.cc
@@ -14,8 +14,8 @@
   VAL_1 = 1,
   VAL_2 = 2,
   VAL_3 = 3,
-  VAL_63 = 63,
-  kMaxValue = 63,
+  VAL_31 = 31,
+  kMaxValue = 31,
 };
 
 // A macro for testing that a std::optional has both a value and that its value
@@ -26,44 +26,44 @@
     EXPECT_EQ(expected, actual.value());     \
   }
 
-// Tests a small enum (one that fits inside a single byte (aka kMaxValue <= 63).
+// Tests a small enum (one that fits inside a single byte (aka kMaxValue <= 31).
 TEST(AXBitsetTest, TestEnum) {
   AXBitset<TestEnum> map;
-  EXPECT_FALSE(map.Has(TestEnum::kMinValue));
+  EXPECT_FALSE(map.Get(TestEnum::kMinValue));
   map.Set(TestEnum::kMinValue, true);
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::kMinValue));
   map.Set(TestEnum::kMinValue, false);
-  EXPECT_OPTIONAL_EQ(false, map.Has(TestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(false, map.Get(TestEnum::kMinValue));
   map.Unset(TestEnum::kMinValue);
-  EXPECT_FALSE(map.Has(TestEnum::kMinValue));
+  EXPECT_FALSE(map.Get(TestEnum::kMinValue));
 
-  EXPECT_FALSE(map.Has(TestEnum::VAL_2));
+  EXPECT_FALSE(map.Get(TestEnum::VAL_2));
   map.Set(TestEnum::VAL_2, true);
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::VAL_2));
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::VAL_2));
   map.Set(TestEnum::VAL_2, false);
-  EXPECT_OPTIONAL_EQ(false, map.Has(TestEnum::VAL_2));
+  EXPECT_OPTIONAL_EQ(false, map.Get(TestEnum::VAL_2));
   map.Unset(TestEnum::VAL_2);
-  EXPECT_FALSE(map.Has(TestEnum::VAL_2));
+  EXPECT_FALSE(map.Get(TestEnum::VAL_2));
 
-  EXPECT_FALSE(map.Has(TestEnum::VAL_63));
-  map.Set(TestEnum::VAL_63, true);
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::VAL_63));
-  map.Set(TestEnum::VAL_63, false);
-  EXPECT_OPTIONAL_EQ(false, map.Has(TestEnum::VAL_63));
-  map.Unset(TestEnum::VAL_63);
-  EXPECT_FALSE(map.Has(TestEnum::VAL_63));
+  EXPECT_FALSE(map.Get(TestEnum::VAL_31));
+  map.Set(TestEnum::VAL_31, true);
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::VAL_31));
+  map.Set(TestEnum::VAL_31, false);
+  EXPECT_OPTIONAL_EQ(false, map.Get(TestEnum::VAL_31));
+  map.Unset(TestEnum::VAL_31);
+  EXPECT_FALSE(map.Get(TestEnum::VAL_31));
 
   map.Set(TestEnum::kMinValue, true);
   map.Set(TestEnum::VAL_2, true);
-  map.Set(TestEnum::VAL_63, true);
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::kMinValue));
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::VAL_2));
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::VAL_63));
-  map.Set(TestEnum::VAL_63, false);
-  EXPECT_OPTIONAL_EQ(false, map.Has(TestEnum::VAL_63));
+  map.Set(TestEnum::VAL_31, true);
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::VAL_2));
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::VAL_31));
+  map.Set(TestEnum::VAL_31, false);
+  EXPECT_OPTIONAL_EQ(false, map.Get(TestEnum::VAL_31));
   map.Unset(TestEnum::kMinValue);
-  EXPECT_FALSE(map.Has(TestEnum::kMinValue));
-  EXPECT_OPTIONAL_EQ(true, map.Has(TestEnum::VAL_2));
+  EXPECT_FALSE(map.Get(TestEnum::kMinValue));
+  EXPECT_OPTIONAL_EQ(true, map.Get(TestEnum::VAL_2));
 }
 
 TEST(AXBitsetTest, ForEach) {
@@ -90,7 +90,7 @@
   EXPECT_EQ(expected_size, map.Size());
 
   map.Set(TestEnum::kMinValue, true);
-  map.Set(TestEnum::VAL_63, false);
+  map.Set(TestEnum::VAL_31, false);
   expected_size = 2;
   EXPECT_EQ(expected_size, map.Size());
 
@@ -99,7 +99,7 @@
   EXPECT_EQ(expected_size, map.Size());
 
   // Unset existing attribute.
-  map.Unset(TestEnum::VAL_63);
+  map.Unset(TestEnum::VAL_31);
   expected_size = 1;
   EXPECT_EQ(expected_size, map.Size());
 }
@@ -114,14 +114,14 @@
   set_b.Set(TestEnum::VAL_1, false);
   set_b.Set(TestEnum::VAL_2, true);
   set_b.Set(TestEnum::VAL_3, true);
-  set_b.Set(TestEnum::VAL_63, false);
+  set_b.Set(TestEnum::VAL_31, false);
 
   set_a.Append(set_b);
 
-  EXPECT_OPTIONAL_EQ(true, set_a.Has(TestEnum::VAL_0));    // No change.
-  EXPECT_OPTIONAL_EQ(false, set_a.Has(TestEnum::VAL_1));   // Overridden.
-  EXPECT_OPTIONAL_EQ(true, set_a.Has(TestEnum::VAL_2));    // Overridden.
-  EXPECT_OPTIONAL_EQ(true, set_a.Has(TestEnum::VAL_3));    // New value.
-  EXPECT_OPTIONAL_EQ(false, set_a.Has(TestEnum::VAL_63));  // New value.
+  EXPECT_OPTIONAL_EQ(true, set_a.Get(TestEnum::VAL_0));    // No change.
+  EXPECT_OPTIONAL_EQ(false, set_a.Get(TestEnum::VAL_1));   // Overridden.
+  EXPECT_OPTIONAL_EQ(true, set_a.Get(TestEnum::VAL_2));    // Overridden.
+  EXPECT_OPTIONAL_EQ(true, set_a.Get(TestEnum::VAL_3));    // New value.
+  EXPECT_OPTIONAL_EQ(false, set_a.Get(TestEnum::VAL_31));  // New value.
 }
 }  // namespace ui
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 67f21fb..3de39f7 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -260,8 +260,8 @@
 
 void AXVectorBoolStore::ForEach(
     base::FunctionRef<void(ax::mojom::BoolAttribute, bool)> callback) const {
-  for (const auto& pair : list_) {
-    callback(pair.first, pair.second);
+  for (const auto& [attr, value] : list_) {
+    callback(attr, value);
   }
 }
 
@@ -296,6 +296,16 @@
   return list_ == other.list_;
 }
 
+void AXVectorBoolStore::PopulateFromBitset(
+    const AXBitset<ax::mojom::BoolAttribute>& source_bitset) {
+  std::vector<std::pair<ax::mojom::BoolAttribute, bool>> pairs;
+  pairs.reserve(source_bitset.Size());
+  source_bitset.ForEach([&pairs](ax::mojom::BoolAttribute attr, bool value) {
+    pairs.emplace_back(attr, value);
+  });
+  list_.container().replace(std::move(pairs));
+}
+
 void AXVectorBoolStore::PopulateFromMap(
     const base::flat_map<ax::mojom::BoolAttribute, bool>& source_map) {
   list_.container() = source_map;
@@ -308,12 +318,11 @@
     : bitset_(other.bitset_) {}
 
 bool AXBitsetBoolStore::Has(ax::mojom::BoolAttribute attribute) const {
-  return bitset_.Has(attribute).has_value();
+  return bitset_.Get(attribute).has_value();
 }
 
 bool AXBitsetBoolStore::Get(ax::mojom::BoolAttribute attribute) const {
-  std::optional<bool> attr = bitset_.Has(attribute);
-  return attr.has_value() ? attr.value() : false;
+  return bitset_.Get(attribute).value_or(false);
 }
 
 void AXBitsetBoolStore::Set(ax::mojom::BoolAttribute attribute, bool value) {
@@ -380,11 +389,16 @@
   return vector;
 }
 
+void AXBitsetBoolStore::PopulateFromBitset(
+    const AXBitset<ax::mojom::BoolAttribute>& source_bitset) {
+  bitset_ = source_bitset;
+}
+
 void AXBitsetBoolStore::PopulateFromMap(
     const base::flat_map<ax::mojom::BoolAttribute, bool>& source_map) {
   AXBitset<ax::mojom::BoolAttribute> temp_bitset;
-  for (const auto& pair : source_map) {
-    temp_bitset.Set(pair.first, pair.second);
+  for (const auto& [attr, value] : source_map) {
+    temp_bitset.Set(attr, value);
   }
   bitset_ = temp_bitset;
 }
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h
index ede1502..5353db8b 100644
--- a/ui/accessibility/ax_node_data.h
+++ b/ui/accessibility/ax_node_data.h
@@ -60,6 +60,8 @@
   virtual void Merge(const AXBoolStore& other) = 0;
   virtual void ForEach(base::FunctionRef<void(ax::mojom::BoolAttribute, bool)>
                            callback) const = 0;
+  virtual void PopulateFromBitset(
+      const AXBitset<ax::mojom::BoolAttribute>& source_bitset) = 0;
   virtual void PopulateFromMap(
       const base::flat_map<ax::mojom::BoolAttribute, bool>& source_map) = 0;
 
@@ -97,6 +99,8 @@
   void ForEach(base::FunctionRef<void(ax::mojom::BoolAttribute, bool)> callback)
       const override;
   void Merge(const AXBoolStore& other) override;
+  void PopulateFromBitset(
+      const AXBitset<ax::mojom::BoolAttribute>& source_bitset) override;
   void PopulateFromMap(const base::flat_map<ax::mojom::BoolAttribute, bool>&
                            source_map) override;
   const AXBitset<ax::mojom::BoolAttribute>& GetBitsetStore() const override;
@@ -129,6 +133,8 @@
   void Merge(const AXBoolStore& other) override;
   void ForEach(base::FunctionRef<void(ax::mojom::BoolAttribute, bool)> callback)
       const override;
+  void PopulateFromBitset(
+      const AXBitset<ax::mojom::BoolAttribute>& source_bitset) override;
   void PopulateFromMap(const base::flat_map<ax::mojom::BoolAttribute, bool>&
                            source_map) override;
   const AXBitset<ax::mojom::BoolAttribute>& GetBitsetStore() const override;
diff --git a/ui/accessibility/mojom/ax_node_data.mojom b/ui/accessibility/mojom/ax_node_data.mojom
index 312cc98..9a35b9df 100644
--- a/ui/accessibility/mojom/ax_node_data.mojom
+++ b/ui/accessibility/mojom/ax_node_data.mojom
@@ -7,7 +7,14 @@
 import "ui/accessibility/ax_enums.mojom";
 import "ui/accessibility/mojom/ax_relative_bounds.mojom";
 
+[Stable, Uuid="88b0e7cb-5a53-4993-9967-d33fb50b484b"]
+struct AXBitsetData {
+  uint32 set_bits;
+  uint32 values;
+};
+
 // See ui::AXNodeData for comments / explanations of these fields.
+// Next version: 2
 [Stable, Uuid="5ee2327f-edc3-4d0e-aa96-6f8ce5720390"]
 struct AXNodeData {
   int32 id;
@@ -17,6 +24,8 @@
   map<ax.mojom.StringAttribute, string> string_attributes;
   map<ax.mojom.IntAttribute, int32> int_attributes;
   map<ax.mojom.FloatAttribute, float> float_attributes;
+  // If bool_attributes_data is present, bool_attributes will be ignored.
+  // TODO: crbug.com/422234724 - Deprecate when the AXBitset experiment is over.
   map<ax.mojom.BoolAttribute, bool> bool_attributes;
   map<ax.mojom.IntListAttribute, array<int32>>
       intlist_attributes;
@@ -25,4 +34,5 @@
   map<string, string> html_attributes;
   array<int32> child_ids;
   ax.mojom.AXRelativeBounds relative_bounds;
+  [MinVersion=1] AXBitsetData? bool_attributes_data;
 };
diff --git a/ui/accessibility/mojom/ax_node_data_mojom_traits.cc b/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
index fd6d8fc4..672a41b7 100644
--- a/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
+++ b/ui/accessibility/mojom/ax_node_data_mojom_traits.cc
@@ -22,6 +22,15 @@
 }  // namespace
 
 // static
+bool StructTraits<ax::mojom::AXBitsetDataDataView,
+                  ui::AXBitset<ax::mojom::BoolAttribute>>::
+    Read(ax::mojom::AXBitsetDataDataView data,
+         ui::AXBitset<ax::mojom::BoolAttribute>* out) {
+  *out = ui::AXBitset<ax::mojom::BoolAttribute>(data.set_bits(), data.values());
+  return true;
+}
+
+// static
 bool StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData>::Read(
     ax::mojom::AXNodeDataDataView data,
     ui::AXNodeData* out) {
@@ -40,11 +49,19 @@
     return false;
   }
 
-  base::flat_map<ax::mojom::BoolAttribute, bool> bool_attributes_from_mojo;
-  if (!data.ReadBoolAttributes(&bool_attributes_from_mojo)) {
+  std::optional<ui::AXBitset<ax::mojom::BoolAttribute>> bitset_from_mojo;
+  if (!data.ReadBoolAttributesData(&bitset_from_mojo)) {
     return false;
   }
-  out->bool_attributes->PopulateFromMap(bool_attributes_from_mojo);
+  if (bitset_from_mojo.has_value()) {
+    out->bool_attributes->PopulateFromBitset(bitset_from_mojo.value());
+  } else {
+    base::flat_map<ax::mojom::BoolAttribute, bool> bool_attributes_from_mojo;
+    if (!data.ReadBoolAttributes(&bool_attributes_from_mojo)) {
+      return false;
+    }
+    out->bool_attributes->PopulateFromMap(bool_attributes_from_mojo);
+  }
 
   auto& intlist_attributes = out->intlist_attributes.container();
   if (!data.ReadIntlistAttributes(&intlist_attributes)) {
diff --git a/ui/accessibility/mojom/ax_node_data_mojom_traits.h b/ui/accessibility/mojom/ax_node_data_mojom_traits.h
index acfda5d..d33c3cc1e 100644
--- a/ui/accessibility/mojom/ax_node_data_mojom_traits.h
+++ b/ui/accessibility/mojom/ax_node_data_mojom_traits.h
@@ -12,6 +12,21 @@
 namespace mojo {
 
 template <>
+struct StructTraits<ax::mojom::AXBitsetDataDataView,
+                    ui::AXBitset<ax::mojom::BoolAttribute>> {
+  static uint32_t set_bits(const ui::AXBitset<ax::mojom::BoolAttribute>& p) {
+    return p.GetSetBits();
+  }
+
+  static uint32_t values(const ui::AXBitset<ax::mojom::BoolAttribute>& p) {
+    return p.GetValues();
+  }
+
+  static bool Read(ax::mojom::AXBitsetDataDataView data,
+                   ui::AXBitset<ax::mojom::BoolAttribute>* out);
+};
+
+template <>
 struct StructTraits<ax::mojom::AXNodeDataDataView, ui::AXNodeData> {
   static int32_t id(const ui::AXNodeData& p) { return p.id; }
   static ax::mojom::Role role(const ui::AXNodeData& p) { return p.role; }
@@ -32,15 +47,22 @@
   static base::flat_map<ax::mojom::BoolAttribute, bool> bool_attributes(
       const ui::AXNodeData& p) {
     if (p.bool_attributes->IsBitset()) {
-      base::flat_map<ax::mojom::BoolAttribute, bool> result;
+      base::flat_map<ax::mojom::BoolAttribute, bool>::container_type result;
       p.bool_attributes->GetBitsetStore().ForEach(
           [&result](ax::mojom::BoolAttribute attr, bool value) {
-            result[attr] = value;
+            result.emplace_back(attr, value);
           });
-      return result;
+      return base::flat_map<ax::mojom::BoolAttribute, bool>(std::move(result));
     }
     return p.bool_attributes->GetVectorStore().container();
   }
+  static std::optional<ui::AXBitset<ax::mojom::BoolAttribute>>
+  bool_attributes_data(const ui::AXNodeData& p) {
+    if (p.bool_attributes->IsBitset()) {
+      return p.bool_attributes->GetBitsetStore();
+    }
+    return std::nullopt;
+  }
   static const base::flat_map<ax::mojom::IntListAttribute,
                               std::vector<int32_t>>&
   intlist_attributes(const ui::AXNodeData& p) {
diff --git a/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java b/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java
index 1d703e2..34c4bc1 100644
--- a/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java
+++ b/ui/android/java/src/org/chromium/ui/base/ClipboardImpl.java
@@ -9,8 +9,6 @@
 import android.content.ClipboardManager;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageInfo;
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -18,7 +16,6 @@
 import android.os.PersistableBundle;
 import android.text.Html;
 import android.text.Spanned;
-import android.text.TextUtils;
 import android.text.style.CharacterStyle;
 import android.text.style.ParagraphStyle;
 import android.text.style.UpdateAppearance;
@@ -113,13 +110,6 @@
         ClipDescription description = mClipboardManager.getPrimaryClipDescription();
         if (description == null) return false;
 
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
-            // On Pre-P, {@link clear()} uses an empty ClipData#newPlainText to clear the clipboard,
-            // which will create an empty MIMETYPE_TEXT_PLAIN in the clipboard, so we need to read
-            // the real clipboard data to check.
-            return !TextUtils.isEmpty(getCoercedText());
-        }
-
         return description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)
                 || description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML)
                 || description.hasMimeType(URL_MIME_TYPE);
@@ -447,8 +437,6 @@
             return;
         }
 
-        grantUriPermission(uri);
-
         // ClipData.newUri may access the disk (for reading mime types), and cause
         // StrictModeDiskReadViolation if do it on UI thread.
         new AsyncTask<ClipData>() {
@@ -529,13 +517,6 @@
 
     @Override
     protected void clear() {
-        // clearPrimaryClip() has been observed to throw unexpected exceptions for Android P (see
-        // crbug/1203377)
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
-            setPrimaryClipNoException(ClipData.newPlainText(null, null));
-            return;
-        }
-
         try {
             mClipboardManager.clearPrimaryClip();
         } catch (Exception e) {
@@ -579,12 +560,11 @@
     /**
      * Tells the C++ Clipboard that the clipboard has changed.
      *
-     * Implements OnPrimaryClipChangedListener to listen for clipboard updates.
+     * <p>Implements OnPrimaryClipChangedListener to listen for clipboard updates.
      */
     @Override
     public void onPrimaryClipChanged() {
         RecordUserAction.record("MobileClipboardChanged");
-        revokeUriPermissionForLastSharedImage();
         notifyPrimaryClipChanged();
     }
 
@@ -622,65 +602,6 @@
     }
 
     /**
-     * Grant permission to access a specific Uri to other packages. For sharing images through the
-     * system’s clipboard, Outside of Android O permissions are already managed properly by the
-     * system. But on Android O, sharing images/files needs to grant permission to each app/packages
-     * individually. Note: Don't forget to revoke the permission once the clipboard is updated.
-     */
-    @SuppressWarnings("QueryPermissionsNeeded")
-    private void grantUriPermission(Uri uri) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P || mImageFileProvider == null) {
-            return;
-        }
-
-        List<PackageInfo> installedPackages = mContext.getPackageManager().getInstalledPackages(0);
-        for (PackageInfo installedPackage : installedPackages) {
-            mContext.grantUriPermission(
-                    installedPackage.packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        }
-    }
-
-    /**
-     * Revoke the permission for previously shared image uri. This operation is only needed for
-     * Android O.
-     */
-    private void revokeUriPermissionForLastSharedImage() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            return;
-        }
-
-        if (mImageFileProvider == null) {
-            // It is ok to not revoke permission. Since |mImageFileProvider| is set very early on
-            // during process init, |mImageFileProvider| == null means we are starting.
-            // ShareImageFileUtils#clearSharedImages will clear cached image files during
-            // startup if they are not being shared. Therefore even if permission is not revoked,
-            // the other package will not get the image. The permission will be revoked later, once
-            // onPrimaryClipChanged triggered. Also, since shared images use timestamp as file
-            // name, the file name will not be reused.
-            return;
-        }
-
-        ImageFileProvider.ClipboardFileMetadata imageMetadata =
-                mImageFileProvider.getLastCopiedImageMetadata();
-        // Exit early if the URI is empty or event onPrimaryClipChanges was caused by sharing
-        // image.
-        if (imageMetadata == null
-                || imageMetadata.uri == null
-                || imageMetadata.uri.equals(Uri.EMPTY)
-                || imageMetadata.uri.equals(getImageUri())) {
-            return;
-        }
-
-        // https://developer.android.com/reference/android/content/Context#revokeUriPermission(android.net.Uri,%20int)
-        // According to the above link, it is not necessary to enumerate all of the packages like
-        // what was done in |grantUriPermission|. Context#revokeUriPermission(Uri, int) will revoke
-        // all permissions.
-        mContext.revokeUriPermission(imageMetadata.uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        // Clear uri to avoid revoke over and over.
-        mImageFileProvider.clearLastCopiedImageMetadata();
-    }
-
-    /**
      * Allows the ClipboardManager Android Service to be replaced with a mock for tests, returning
      * the original so that it can be restored.
      */
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
index 45d6ab2..b8097b5 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -289,10 +289,7 @@
                 }
             }
 
-            int gestureClassification = 0;
-            if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
-                gestureClassification = event.getClassification();
-            }
+            int gestureClassification = event.getClassification();
 
             final boolean consumed =
                     EventForwarderJni.get()
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index ccb905c6..6220bfc1 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -260,21 +260,16 @@
         mDisplayAndroid = display;
         mDisplayAndroid.addObserver(this);
 
-        // Using this setting is gated to Q due to bugs on Razer phones which can freeze the device
-        // if the API is used. See crbug.com/990646.
         // Disable refresh rate change on TV platforms, as it may cause black screen flicker due to
         // display mode changes.
-        mAllowChangeRefreshRate = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !isTv(context);
+        mAllowChangeRefreshRate = !isTv(context);
 
         // Multiple refresh rate support is only available on M+.
         recomputeSupportedRefreshRates();
 
         // Configuration.isDisplayServerWideColorGamut must be queried from the window's context.
-        // Because of crbug.com/756180, many devices report true for isScreenWideColorGamut in
-        // 8.0.0, even when they don't actually support wide color gamut.
         // TODO(boliu): Observe configuration changes to update the value of isScreenWideColorGamut.
-        if (!Build.VERSION.RELEASE.equals("8.0.0")
-                && ContextUtils.activityFromContext(context) != null) {
+        if (ContextUtils.activityFromContext(context) != null) {
             Configuration configuration = context.getResources().getConfiguration();
             boolean isScreenWideColorGamut = configuration.isScreenWideColorGamut();
             display.updateIsDisplayServerWideColorGamut(isScreenWideColorGamut);
@@ -943,7 +938,6 @@
     // gamut (on supported hardware and os). However it is important for embedders like WebView
     // which do not make the wide gamut decision to check this at run time.
     private boolean getWindowIsWideColorGamut() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return false;
         Window window = getWindow();
         if (window == null) return false;
         return window.isWideColorGamut();
@@ -1101,12 +1095,6 @@
 
     @CalledByNative
     public void setWideColorEnabled(boolean enabled) {
-        // Although this API was added in Android O, it was buggy.
-        // Restrict to Android Q, where it was fixed.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
-            assert !enabled;
-            return;
-        }
         Window window = getWindow();
         if (window == null) return;
 
diff --git a/ui/base/win/event_creation_utils.cc b/ui/base/win/event_creation_utils.cc
index ea6e816a..e4905c6e 100644
--- a/ui/base/win/event_creation_utils.cc
+++ b/ui/base/win/event_creation_utils.cc
@@ -18,10 +18,15 @@
   INPUT input = {INPUT_MOUSE};
   // Get the max screen coordinate for use in computing the normalized absolute
   // coordinates required by SendInput.
-  const int screen_width = ::GetSystemMetrics(SM_CXSCREEN);
-  const int screen_height = ::GetSystemMetrics(SM_CYSCREEN);
-  int screen_x = std::clamp(point.x(), 0, screen_width - 1);
-  int screen_y = std::clamp(point.y(), 0, screen_height - 1);
+  const int screen_left = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
+  const int screen_top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
+  const int screen_width = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
+  const int screen_height = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
+
+  int screen_x =
+      std::clamp(point.x(), screen_left, screen_left + screen_width - 1);
+  int screen_y =
+      std::clamp(point.y(), screen_top, screen_top + screen_height - 1);
 
   // In normalized absolute coordinates, (0, 0) maps onto the upper-left corner
   // of the display surface, while (65535, 65535) maps onto the lower-right
@@ -32,10 +37,12 @@
   // Form the input data containing the normalized absolute coordinates. As of
   // Windows 10 Fall Creators Update, moving to an absolute position of zero
   // does not work. It seems that moving to 1,1 does, though.
-  input.mi.dx = static_cast<LONG>(std::max(
-      1.0, std::ceil(screen_x * (kNormalizedScreenSize / screen_width))));
-  input.mi.dy = static_cast<LONG>(std::max(
-      1.0, std::ceil(screen_y * (kNormalizedScreenSize / screen_height))));
+  input.mi.dx = static_cast<LONG>(
+      std::max(1.0, std::ceil((screen_x - screen_left) *
+                              (kNormalizedScreenSize / screen_width))));
+  input.mi.dy = static_cast<LONG>(
+      std::max(1.0, std::ceil((screen_y - screen_top) *
+                              (kNormalizedScreenSize / screen_height))));
   input.mi.dwFlags = static_cast<DWORD>(flags | MOUSEEVENTF_ABSOLUTE);
   return ::SendInput(1, &input, sizeof(input)) == 1;
 }
diff --git a/ui/color/dynamic_color/palette_factory.h b/ui/color/dynamic_color/palette_factory.h
index e9be183..75ae73f 100644
--- a/ui/color/dynamic_color/palette_factory.h
+++ b/ui/color/dynamic_color/palette_factory.h
@@ -21,6 +21,10 @@
     SkColor seed_color,
     ColorProviderKey::SchemeVariant variant);
 
+// Represents the number of shades needed to be generated for each hue specified
+// in the `tab_group_color_palette` key of `theme` key in manifest.json.
+inline constexpr size_t kGeneratedShadesCount = 11;
+
 }  // namespace ui
 
 #endif  // UI_COLOR_DYNAMIC_COLOR_PALETTE_FACTORY_H_
diff --git a/ui/events/android/motion_event_android_source.h b/ui/events/android/motion_event_android_source.h
index 1c7a52c8..87a6dcd 100644
--- a/ui/events/android/motion_event_android_source.h
+++ b/ui/events/android/motion_event_android_source.h
@@ -27,9 +27,12 @@
   virtual float GetTouchMinorPix(size_t pointer_index) const = 0;
   virtual float GetRawOrientation(size_t pointer_index) const = 0;
   virtual float GetPressure(size_t pointer_index) const = 0;
+  virtual float GetAxisHscroll(size_t pointer_index) const = 0;
+  virtual float GetAxisVscroll(size_t pointer_index) const = 0;
   virtual float GetRawTilt(size_t pointer_index) const = 0;
   virtual MotionEvent::ToolType GetToolType(size_t pointer_index) const = 0;
-
+  virtual int GetActionMasked() const = 0;
+  virtual int GetButtonState() const = 0;
   virtual base::TimeTicks GetHistoricalEventTime(
       size_t historical_index) const = 0;
   virtual float GetHistoricalTouchMajorPix(size_t pointer_index,
diff --git a/ui/events/android/motion_event_android_source_java.cc b/ui/events/android/motion_event_android_source_java.cc
index 4473324..526ca06 100644
--- a/ui/events/android/motion_event_android_source_java.cc
+++ b/ui/events/android/motion_event_android_source_java.cc
@@ -72,6 +72,18 @@
                                                        event_, pointer_index);
 }
 
+float MotionEventAndroidSourceJava::GetAxisHscroll(size_t pointer_index) const {
+  return Java_MotionEvent_getAxisValue(AttachCurrentThread(), event_,
+                                       JNI_MotionEvent::AXIS_HSCROLL,
+                                       pointer_index);
+}
+
+float MotionEventAndroidSourceJava::GetAxisVscroll(size_t pointer_index) const {
+  return Java_MotionEvent_getAxisValue(AttachCurrentThread(), event_,
+                                       JNI_MotionEvent::AXIS_VSCROLL,
+                                       pointer_index);
+}
+
 float MotionEventAndroidSourceJava::GetRawTilt(size_t pointer_index) const {
   return Java_MotionEvent_getAxisValue(
       AttachCurrentThread(), event_, JNI_MotionEvent::AXIS_TILT, pointer_index);
@@ -83,6 +95,16 @@
       AttachCurrentThread(), event_, pointer_index));
 }
 
+int MotionEventAndroidSourceJava::GetActionMasked() const {
+  return JNI_MotionEvent::Java_MotionEvent_getActionMasked(
+      AttachCurrentThread(), event_);
+}
+
+int MotionEventAndroidSourceJava::GetButtonState() const {
+  return JNI_MotionEvent::Java_MotionEvent_getButtonState(AttachCurrentThread(),
+                                                          event_);
+}
+
 base::TimeTicks MotionEventAndroidSourceJava::GetHistoricalEventTime(
     size_t historical_index) const {
   jlong time_ms = JNI_MotionEvent::Java_MotionEvent_getHistoricalEventTime(
diff --git a/ui/events/android/motion_event_android_source_java.h b/ui/events/android/motion_event_android_source_java.h
index 8bdd712..94a707d 100644
--- a/ui/events/android/motion_event_android_source_java.h
+++ b/ui/events/android/motion_event_android_source_java.h
@@ -33,8 +33,12 @@
   float GetTouchMinorPix(size_t pointer_index) const override;
   float GetRawOrientation(size_t pointer_index) const override;
   float GetPressure(size_t pointer_index) const override;
+  float GetAxisHscroll(size_t pointer_index) const override;
+  float GetAxisVscroll(size_t pointer_index) const override;
   float GetRawTilt(size_t pointer_index) const override;
   MotionEvent::ToolType GetToolType(size_t pointer_index) const override;
+  int GetActionMasked() const override;
+  int GetButtonState() const override;
   base::TimeTicks GetHistoricalEventTime(
       size_t historical_index) const override;
   float GetHistoricalTouchMajorPix(size_t pointer_index,
diff --git a/ui/events/android/motion_event_android_source_native.cc b/ui/events/android/motion_event_android_source_native.cc
index e56004b..e64f015d 100644
--- a/ui/events/android/motion_event_android_source_native.cc
+++ b/ui/events/android/motion_event_android_source_native.cc
@@ -51,6 +51,18 @@
   return AMotionEvent_getPressure(event_.a_input_event(), pointer_index);
 }
 
+float MotionEventAndroidSourceNative::GetAxisHscroll(
+    size_t pointer_index) const {
+  return AMotionEvent_getAxisValue(event_.a_input_event(),
+                                   AMOTION_EVENT_AXIS_HSCROLL, pointer_index);
+}
+
+float MotionEventAndroidSourceNative::GetAxisVscroll(
+    size_t pointer_index) const {
+  return AMotionEvent_getAxisValue(event_.a_input_event(),
+                                   AMOTION_EVENT_AXIS_VSCROLL, pointer_index);
+}
+
 float MotionEventAndroidSourceNative::GetRawTilt(size_t pointer_index) const {
   return AMotionEvent_getAxisValue(event_.a_input_event(),
                                    AMOTION_EVENT_AXIS_TILT, pointer_index);
@@ -62,6 +74,15 @@
       AMotionEvent_getToolType(event_.a_input_event(), pointer_index));
 }
 
+int MotionEventAndroidSourceNative::GetActionMasked() const {
+  return AMotionEvent_getAction(event_.a_input_event()) &
+         AMOTION_EVENT_ACTION_MASK;
+}
+
+int MotionEventAndroidSourceNative::GetButtonState() const {
+  return AMotionEvent_getButtonState(event_.a_input_event());
+}
+
 base::TimeTicks MotionEventAndroidSourceNative::GetHistoricalEventTime(
     size_t historical_index) const {
   return base::TimeTicks::FromJavaNanoTime(AMotionEvent_getHistoricalEventTime(
diff --git a/ui/events/android/motion_event_android_source_native.h b/ui/events/android/motion_event_android_source_native.h
index 2f257bc8..3832a3a 100644
--- a/ui/events/android/motion_event_android_source_native.h
+++ b/ui/events/android/motion_event_android_source_native.h
@@ -33,8 +33,12 @@
   float GetTouchMinorPix(size_t pointer_index) const override;
   float GetRawOrientation(size_t pointer_index) const override;
   float GetPressure(size_t pointer_index) const override;
+  float GetAxisHscroll(size_t pointer_index) const override;
+  float GetAxisVscroll(size_t pointer_index) const override;
   float GetRawTilt(size_t pointer_index) const override;
   MotionEvent::ToolType GetToolType(size_t pointer_index) const override;
+  int GetActionMasked() const override;
+  int GetButtonState() const override;
   base::TimeTicks GetHistoricalEventTime(
       size_t historical_index) const override;
   float GetHistoricalTouchMajorPix(size_t pointer_index,
diff --git a/ui/gl/android/surface_texture.cc b/ui/gl/android/surface_texture.cc
index 524f133..d633b593 100644
--- a/ui/gl/android/surface_texture.cc
+++ b/ui/gl/android/surface_texture.cc
@@ -87,7 +87,7 @@
 void SurfaceTexture::GetTransformMatrix(base::span<float, 16> mtx) {
   JNIEnv* env = base::android::AttachCurrentThread();
 
-  base::android::ScopedJavaLocalRef<jfloatArray> jmatrix(
+  auto jmatrix = base::android::ScopedJavaLocalRef<jfloatArray>::Adopt(
       env, env->NewFloatArray(16));
   Java_ChromeSurfaceTexture_getTransformMatrix(env, j_surface_texture_,
                                                jmatrix);
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
index cd6973b..91d040d 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -26,16 +26,6 @@
 
 namespace {
 
-void OnBufferCreatedOnDrmThread(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    DrmThreadProxy::CreateBufferAsyncCallback callback,
-    std::unique_ptr<GbmBuffer> buffer,
-    scoped_refptr<DrmFramebuffer> framebuffer) {
-  task_runner->PostTask(FROM_HERE,
-                        base::BindOnce(std::move(callback), std::move(buffer),
-                                       std::move(framebuffer)));
-}
-
 class GbmDeviceGenerator : public DrmDeviceGenerator {
  public:
   GbmDeviceGenerator() = default;
@@ -99,26 +89,6 @@
                               base::Unretained(&drm_thread_), std::move(task)));
 }
 
-void DrmThreadProxy::CreateBufferAsync(gfx::AcceleratedWidget widget,
-                                       const gfx::Size& size,
-                                       gfx::BufferFormat format,
-                                       gfx::BufferUsage usage,
-                                       uint32_t flags,
-                                       CreateBufferAsyncCallback callback) {
-  DCHECK(drm_thread_.task_runner())
-      << "no task runner! in DrmThreadProxy::CreateBufferAsync";
-  base::OnceClosure task = base::BindOnce(
-      &DrmThread::CreateBufferAsync, base::Unretained(&drm_thread_), widget,
-      size, format, usage, flags,
-      base::BindOnce(OnBufferCreatedOnDrmThread,
-                     base::SingleThreadTaskRunner::GetCurrentDefault(),
-                     std::move(callback)));
-  drm_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
-                     base::Unretained(&drm_thread_), std::move(task), nullptr));
-}
-
 void DrmThreadProxy::CreateBufferFromHandle(
     gfx::AcceleratedWidget widget,
     const gfx::Size& size,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
index ca4684b..0cd0212 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
@@ -51,16 +51,6 @@
                     std::unique_ptr<GbmBuffer>* buffer,
                     scoped_refptr<DrmFramebuffer>* framebuffer);
 
-  using CreateBufferAsyncCallback =
-      base::OnceCallback<void(std::unique_ptr<GbmBuffer>,
-                              scoped_refptr<DrmFramebuffer>)>;
-  void CreateBufferAsync(gfx::AcceleratedWidget widget,
-                         const gfx::Size& size,
-                         gfx::BufferFormat format,
-                         gfx::BufferUsage usage,
-                         uint32_t flags,
-                         CreateBufferAsyncCallback callback);
-
   void CreateBufferFromHandle(gfx::AcceleratedWidget widget,
                               const gfx::Size& size,
                               gfx::BufferFormat format,
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 62254cc..56efb3e 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -245,18 +245,6 @@
   return supported_buffer_formats;
 }
 
-void OnNativePixmapCreated(GbmSurfaceFactory::NativePixmapCallback callback,
-                           base::WeakPtr<GbmSurfaceFactory> weak_ptr,
-                           std::unique_ptr<GbmBuffer> buffer,
-                           scoped_refptr<DrmFramebuffer> framebuffer) {
-  if (!weak_ptr || !buffer) {
-    std::move(callback).Run(nullptr);
-  } else {
-    std::move(callback).Run(base::MakeRefCounted<GbmPixmap>(
-        weak_ptr.get(), std::move(buffer), std::move(framebuffer)));
-  }
-}
-
 }  // namespace
 
 GbmSurfaceFactory::GbmSurfaceFactory(DrmThreadProxy* drm_thread_proxy)
@@ -414,19 +402,6 @@
                                          std::move(framebuffer));
 }
 
-void GbmSurfaceFactory::CreateNativePixmapAsync(
-    gfx::AcceleratedWidget widget,
-    gpu::VulkanDeviceQueue* device_queue,
-    gfx::Size size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    NativePixmapCallback callback) {
-  drm_thread_proxy_->CreateBufferAsync(
-      widget, size, format, usage, 0 /* flags */,
-      base::BindOnce(OnNativePixmapCreated, std::move(callback),
-                     weak_factory_.GetWeakPtr()));
-}
-
 scoped_refptr<gfx::NativePixmap>
 GbmSurfaceFactory::CreateNativePixmapFromHandleInternal(
     gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index 6b46b4b..8cc64ab 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -67,12 +67,6 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       std::optional<gfx::Size> framebuffer_size = std::nullopt) override;
-  void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
-                               gpu::VulkanDeviceQueue* device_queue,
-                               gfx::Size size,
-                               gfx::BufferFormat format,
-                               gfx::BufferUsage usage,
-                               NativePixmapCallback callback) override;
   scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
       gfx::AcceleratedWidget widget,
       gfx::Size size,
diff --git a/ui/ozone/platform/flatland/flatland_surface_factory.cc b/ui/ozone/platform/flatland/flatland_surface_factory.cc
index cfbacd2..c5539b9 100644
--- a/ui/ozone/platform/flatland/flatland_surface_factory.cc
+++ b/ui/ozone/platform/flatland/flatland_surface_factory.cc
@@ -178,17 +178,6 @@
                                                             format, usage);
 }
 
-void FlatlandSurfaceFactory::CreateNativePixmapAsync(
-    gfx::AcceleratedWidget widget,
-    gpu::VulkanDeviceQueue* device_queue,
-    gfx::Size size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    NativePixmapCallback callback) {
-  std::move(callback).Run(
-      CreateNativePixmap(widget, device_queue, size, format, usage));
-}
-
 scoped_refptr<gfx::NativePixmap>
 FlatlandSurfaceFactory::CreateNativePixmapFromHandle(
     gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/platform/flatland/flatland_surface_factory.h b/ui/ozone/platform/flatland/flatland_surface_factory.h
index 88b61c5..4b06afa 100644
--- a/ui/ozone/platform/flatland/flatland_surface_factory.h
+++ b/ui/ozone/platform/flatland/flatland_surface_factory.h
@@ -53,12 +53,6 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       std::optional<gfx::Size> framebuffer_size = std::nullopt) override;
-  void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
-                               gpu::VulkanDeviceQueue* device_queue,
-                               gfx::Size size,
-                               gfx::BufferFormat format,
-                               gfx::BufferUsage usage,
-                               NativePixmapCallback callback) override;
   scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
       gfx::AcceleratedWidget widget,
       gfx::Size size,
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
index 0f747b75..82124ecf 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc
@@ -282,19 +282,6 @@
   return nullptr;
 }
 
-void WaylandSurfaceFactory::CreateNativePixmapAsync(
-    gfx::AcceleratedWidget widget,
-    gpu::VulkanDeviceQueue* device_queue,
-    gfx::Size size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    NativePixmapCallback callback) {
-  // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
-  // and return the result with the provided callback.
-  std::move(callback).Run(
-      CreateNativePixmap(widget, device_queue, size, format, usage));
-}
-
 scoped_refptr<gfx::NativePixmap>
 WaylandSurfaceFactory::CreateNativePixmapFromHandle(
     gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
index c3ab19a..4a85968 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory.h
@@ -47,12 +47,6 @@
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
       std::optional<gfx::Size> framebuffer_size = std::nullopt) override;
-  void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
-                               gpu::VulkanDeviceQueue* device_queue,
-                               gfx::Size size,
-                               gfx::BufferFormat format,
-                               gfx::BufferUsage usage,
-                               NativePixmapCallback callback) override;
   scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
       gfx::AcceleratedWidget widget,
       gfx::Size size,
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
index 55854de..1307289 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
@@ -42,8 +42,7 @@
 
   // Non-owned pointer, which is used to bind a mojo pointer to the
   // WaylandBufferManagerHost.
-  const raw_ptr<WaylandBufferManagerHost, LeakedDanglingUntriaged>
-      buffer_manager_host_;
+  const raw_ptr<WaylandBufferManagerHost> buffer_manager_host_;
 
   GpuHostBindInterfaceCallback binder_;
   GpuHostTerminateCallback terminate_callback_;
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index fff2533..7d6d6c3a 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -305,11 +305,6 @@
   cursor_->UpdateBitmap(bitmaps, hotspot_in_dips, buffer_scale);
 }
 
-void WaylandConnection::ResetCursor() {
-  cursor_.reset();
-  cursor_position_.reset();
-}
-
 bool WaylandConnection::IsDragInProgress() const {
   // An active drag requires a seat exist.
   return seat_ && data_device_manager_ &&
@@ -431,7 +426,8 @@
       zwp_pointer_gestures_->Init();
     }
   } else {
-    ResetCursor();
+    cursor_.reset();
+    cursor_position_.reset();
   }
 }
 
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.h b/ui/ozone/platform/wayland/host/wayland_connection.h
index 1a1aefd..ed4d61c0 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.h
+++ b/ui/ozone/platform/wayland/host/wayland_connection.h
@@ -149,8 +149,6 @@
                        const gfx::Point& hotspot_in_dips,
                        int buffer_scale);
 
-  void ResetCursor();
-
   WaylandEventSource* event_source() const { return event_source_.get(); }
 
   WaylandSeat* seat() const { return seat_.get(); }
@@ -439,7 +437,6 @@
   // capabilities to create wl_buffers.
   std::unique_ptr<WaylandBufferFactory> buffer_factory_;
 
-  std::unique_ptr<WaylandSeat> seat_;
   std::unique_ptr<WaylandCursor> cursor_;
   std::unique_ptr<WaylandDataDeviceManager> data_device_manager_;
   std::unique_ptr<WaylandOutputManager> output_manager_;
@@ -451,6 +448,7 @@
   std::unique_ptr<WaylandZwpRelativePointerManager>
       zwp_relative_pointer_manager_;
   std::unique_ptr<WaylandZwpPointerGestures> zwp_pointer_gestures_;
+  std::unique_ptr<WaylandSeat> seat_;
   std::unique_ptr<WaylandBufferManagerHost> buffer_manager_host_;
   std::unique_ptr<XdgActivation> xdg_activation_;
   std::unique_ptr<XdgForeignWrapper> xdg_foreign_;
diff --git a/ui/ozone/platform/wayland/host/wayland_cursor.h b/ui/ozone/platform/wayland/host/wayland_cursor.h
index 29caba6..83087884 100644
--- a/ui/ozone/platform/wayland/host/wayland_cursor.h
+++ b/ui/ozone/platform/wayland/host/wayland_cursor.h
@@ -89,7 +89,7 @@
                        uint32_t hotspot_x_dip,
                        uint32_t hotspot_y_dip);
 
-  const raw_ptr<WaylandPointer> pointer_;
+  const raw_ptr<WaylandPointer, DanglingUntriaged> pointer_;
   const raw_ptr<WaylandConnection> connection_;
   const wl::Object<wl_surface> pointer_surface_;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.h b/ui/ozone/platform/wayland/host/wayland_data_device.h
index d94917fc..128baea 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.h
@@ -121,7 +121,7 @@
   // The wl_data_device wrapped by this WaylandDataDevice.
   wl::Object<wl_data_device> data_device_;
 
-  raw_ptr<DragDelegate, DanglingUntriaged> drag_delegate_ = nullptr;
+  raw_ptr<DragDelegate> drag_delegate_ = nullptr;
 
   // There are two separate data offers at a time, the drag offer and the
   // selection offer, each with independent lifetimes. When we receive a new
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index 1e36b44..be96edfe 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -130,6 +130,7 @@
 
 WaylandDataDragController::~WaylandDataDragController() {
   window_manager_->RemoveObserver(this);
+  data_device_manager_->GetDevice()->ResetDragDelegate();
 }
 
 bool WaylandDataDragController::StartSession(const OSExchangeData& data,
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index 27a98e6..e1239e6b 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -281,7 +281,7 @@
   std::unique_ptr<WaylandSurface> origin_surface_;
 
   // Current window under pointer.
-  raw_ptr<WaylandWindow, DanglingUntriaged> window_ = nullptr;
+  raw_ptr<WaylandWindow> window_ = nullptr;
 
   // The most recent location received while dragging the data.
   gfx::PointF last_drag_location_;
diff --git a/ui/ozone/platform/wayland/host/wayland_event_source.cc b/ui/ozone/platform/wayland/host/wayland_event_source.cc
index a3e14fa..4cc15e84 100644
--- a/ui/ozone/platform/wayland/host/wayland_event_source.cc
+++ b/ui/ozone/platform/wayland/host/wayland_event_source.cc
@@ -127,7 +127,7 @@
   TouchPoint(gfx::PointF location, WaylandWindow* current_window);
   ~TouchPoint() = default;
 
-  raw_ptr<WaylandWindow, DanglingUntriaged> window;
+  raw_ptr<WaylandWindow> window;
   gfx::PointF last_known_location;
 };
 
diff --git a/ui/ozone/platform/wayland/host/wayland_menu_utils.h b/ui/ozone/platform/wayland/host/wayland_menu_utils.h
index a7e55111..4540ba7 100644
--- a/ui/ozone/platform/wayland/host/wayland_menu_utils.h
+++ b/ui/ozone/platform/wayland/host/wayland_menu_utils.h
@@ -22,7 +22,7 @@
   int GetCurrentKeyModifiers() const override;
 
  private:
-  const raw_ptr<WaylandConnection, LeakedDanglingUntriaged> connection_;
+  const raw_ptr<WaylandConnection> connection_;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_pointer.cc b/ui/ozone/platform/wayland/host/wayland_pointer.cc
index 2b7e785..b4e8e01 100644
--- a/ui/ozone/platform/wayland/host/wayland_pointer.cc
+++ b/ui/ozone/platform/wayland/host/wayland_pointer.cc
@@ -55,9 +55,6 @@
 }
 
 WaylandPointer::~WaylandPointer() {
-  // If a cursor already exists, we need to reset it first before
-  // destroying the pointer to prevent dangling references.
-  connection_->ResetCursor();
   // Even though, WaylandPointer::Leave is always called when Wayland destroys
   // wl_pointer, it's better to be explicit as some Wayland compositors may have
   // bugs.
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index 3aec789..dcb81cc7 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -129,7 +129,10 @@
   }
 }
 
-WaylandScreen::~WaylandScreen() = default;
+WaylandScreen::~WaylandScreen() {
+  // Destroy the idle inhibitor early.  See https://crbug.com/433643249
+  idle_inhibitor_.reset();
+}
 
 void WaylandScreen::OnOutputAddedOrUpdated(
     const WaylandOutput::Metrics& metrics) {
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.h b/ui/ozone/platform/wayland/host/wayland_subsurface.h
index 8360829..7a244925 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.h
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.h
@@ -74,7 +74,7 @@
   const raw_ptr<WaylandConnection> connection_;
   // |parent_| refers to the WaylandWindow whose wl_surface is the parent to
   // this subsurface.
-  const raw_ptr<WaylandWindow, AcrossTasksDanglingUntriaged> parent_;
+  const raw_ptr<WaylandWindow> parent_;
   bool visible_ = false;
 };
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 5001bfc6..cae0a37b 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -157,7 +157,9 @@
   DCHECK(keyboard_delegate_);
 }
 
-WaylandWindowDragController::~WaylandWindowDragController() = default;
+WaylandWindowDragController::~WaylandWindowDragController() {
+  data_device_manager_->GetDevice()->ResetDragDelegate();
+}
 
 bool WaylandWindowDragController::StartDragSession(
     WaylandToplevelWindow* origin,
diff --git a/ui/ozone/platform/wayland/test/test_output.h b/ui/ozone/platform/wayland/test/test_output.h
index b50206c..7b6536b 100644
--- a/ui/ozone/platform/wayland/test/test_output.h
+++ b/ui/ozone/platform/wayland/test/test_output.h
@@ -82,7 +82,7 @@
 
   TestOutputMetrics metrics_;
 
-  raw_ptr<TestZXdgOutput, DanglingUntriaged> xdg_output_ = nullptr;
+  raw_ptr<TestZXdgOutput> xdg_output_ = nullptr;
 };
 
 }  // namespace wl
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc
index 8ac128e..43f87cf4 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -239,19 +239,6 @@
       ->CanCreateNativePixmapForFormat(format);
 }
 
-void X11SurfaceFactory::CreateNativePixmapAsync(
-    gfx::AcceleratedWidget widget,
-    gpu::VulkanDeviceQueue* device_queue,
-    gfx::Size size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    NativePixmapCallback callback) {
-  // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
-  // and return the result with the provided callback.
-  std::move(callback).Run(
-      CreateNativePixmap(widget, device_queue, size, format, usage));
-}
-
 scoped_refptr<gfx::NativePixmap>
 X11SurfaceFactory::CreateNativePixmapFromHandle(
     gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/platform/x11/x11_surface_factory.h b/ui/ozone/platform/x11/x11_surface_factory.h
index fdf3b0f..1d53094 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.h
+++ b/ui/ozone/platform/x11/x11_surface_factory.h
@@ -44,12 +44,6 @@
       gfx::BufferUsage usage,
       std::optional<gfx::Size> framebuffer_size = std::nullopt) override;
   bool CanCreateNativePixmapForFormat(gfx::BufferFormat format) override;
-  void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
-                               gpu::VulkanDeviceQueue* device_queue,
-                               gfx::Size size,
-                               gfx::BufferFormat format,
-                               gfx::BufferUsage usage,
-                               NativePixmapCallback callback) override;
   scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
       gfx::AcceleratedWidget widget,
       gfx::Size size,
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
index 0d40ad3..b287afd 100644
--- a/ui/ozone/public/surface_factory_ozone.cc
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -95,16 +95,6 @@
   return true;
 }
 
-void SurfaceFactoryOzone::CreateNativePixmapAsync(
-    gfx::AcceleratedWidget widget,
-    gpu::VulkanDeviceQueue* device_queue,
-    gfx::Size size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    NativePixmapCallback callback) {
-  std::move(callback).Run(nullptr);
-}
-
 scoped_refptr<gfx::NativePixmap>
 SurfaceFactoryOzone::CreateNativePixmapFromHandle(
     gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h
index c6c41a1..2975509 100644
--- a/ui/ozone/public/surface_factory_ozone.h
+++ b/ui/ozone/public/surface_factory_ozone.h
@@ -154,16 +154,6 @@
 
   virtual bool CanCreateNativePixmapForFormat(gfx::BufferFormat format);
 
-  // Similar to CreateNativePixmap, but returns the result asynchronously.
-  using NativePixmapCallback =
-      base::OnceCallback<void(scoped_refptr<gfx::NativePixmap>)>;
-  virtual void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
-                                       gpu::VulkanDeviceQueue* device_queue,
-                                       gfx::Size size,
-                                       gfx::BufferFormat format,
-                                       gfx::BufferUsage usage,
-                                       NativePixmapCallback callback);
-
   // Create a single native buffer from an existing handle. Takes ownership of
   // |handle| and can be called on any thread.
   virtual scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
diff --git a/ui/shell_dialogs/select_file_dialog_android.cc b/ui/shell_dialogs/select_file_dialog_android.cc
index 92b58db2..5ce0161c 100644
--- a/ui/shell_dialogs/select_file_dialog_android.cc
+++ b/ui/shell_dialogs/select_file_dialog_android.cc
@@ -88,13 +88,13 @@
   jsize length = env->GetArrayLength(filepaths.obj());
   DCHECK(length == env->GetArrayLength(display_names.obj()));
   for (int i = 0; i < length; ++i) {
-    ScopedJavaLocalRef<jstring> path_ref(
+    auto path_ref = ScopedJavaLocalRef<jstring>::Adopt(
         env,
         static_cast<jstring>(env->GetObjectArrayElement(filepaths.obj(), i)));
     base::FilePath file_path =
         base::FilePath(ConvertJavaStringToUTF8(env, path_ref));
 
-    ScopedJavaLocalRef<jstring> display_name_ref(
+    auto display_name_ref = ScopedJavaLocalRef<jstring>::Adopt(
         env, static_cast<jstring>(
                  env->GetObjectArrayElement(display_names.obj(), i)));
     std::string display_name =
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 88c3981b..a6bf202a 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -1629,7 +1629,10 @@
   public_deps = [ "//ui/base/mojom:mojom" ]
 
   if (is_win) {
-    sources += [ "accessibility/ax_system_caret_win_interactive_uitest.cc" ]
+    sources += [
+      "accessibility/ax_system_caret_win_interactive_uitest.cc",
+      "win/hwnd_message_handler_interactive_uitest.cc",
+    ]
   }
 
   if (is_mac) {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 7647828..da7c545 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -150,15 +150,18 @@
 void DesktopWindowTreeHostWin::StartTouchDrag(gfx::Point screen_point) {
   // Send a mouse down and mouse move before do drag drop runs its own event
   // loop. This is required for ::DoDragDrop to start the drag.
-  ui::SendMouseEvent(screen_point, MOUSEEVENTF_LEFTDOWN);
-  ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE);
+  ui::SendMouseEvent(screen_point,
+                     (MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_VIRTUALDESK));
+  ui::SendMouseEvent(screen_point,
+                     (MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK));
   in_touch_drag_ = true;
 }
 
 void DesktopWindowTreeHostWin::FinishTouchDrag(gfx::Point screen_point) {
   if (in_touch_drag_) {
     in_touch_drag_ = false;
-    ui::SendMouseEvent(screen_point, MOUSEEVENTF_LEFTUP);
+    ui::SendMouseEvent(screen_point,
+                       (MOUSEEVENTF_LEFTUP | MOUSEEVENTF_VIRTUALDESK));
   }
 }
 
@@ -1191,7 +1194,8 @@
     // to mouse pointer events. The drag controller (`DesktopDragDropClientWin`)
     // will manage gesture states until a drop happens.
     if (event->type() == ui::EventType::kTouchMoved) {
-      ui::SendMouseEvent(screen_point, MOUSEEVENTF_MOVE);
+      ui::SendMouseEvent(screen_point,
+                         (MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK));
     } else if (event->type() == ui::EventType::kTouchReleased) {
       FinishTouchDrag(screen_point);
     }
diff --git a/ui/views/win/DEPS b/ui/views/win/DEPS
index 18fa356..35d2c03e 100644
--- a/ui/views/win/DEPS
+++ b/ui/views/win/DEPS
@@ -1,6 +1,9 @@
 # hwnd_util is allowed to include ui/views because it has separate
 # implementations for win and aura.
 specific_include_rules = {
+  "hwnd_message_handler_interactive_uitest.cc": [
+    "+ui/views/test/widget_test.h"
+  ],
   "hwnd_util.*": [
     "+ui/views",
   ],
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 80333b2..6c7e129 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -297,6 +297,23 @@
   return ui::GetModifiersFromKeyState() | flags;
 }
 
+// Maps HWNDs to their owners.
+using WindowOwnerMap = base::flat_map<HWND, std::vector<HWND>>;
+
+// Callback for GetOwnedWindows(). For each window checks for an owner. If an
+// owner exists, it adds the window to the owner's list in the map.
+BOOL CALLBACK EnumOwnedWindowsProc(HWND hwnd, LPARAM l_param) {
+  HWND owner = ::GetWindow(hwnd, GW_OWNER);
+  if (owner) {
+    // The LPARAM is a direct pointer to our flat_map.
+    WindowOwnerMap* window_owner_map =
+        reinterpret_cast<WindowOwnerMap*>(l_param);
+    // Create an entry if it doesn't exist.
+    (*window_owner_map)[owner].push_back(hwnd);
+  }
+  return TRUE;  // Continue enumeration.
+}
+
 constexpr auto kTouchDownContextResetTimeout = base::Milliseconds(500);
 
 // Windows does not flag synthesized mouse messages from touch or pen in all
@@ -615,6 +632,43 @@
   }
 }
 
+std::vector<HWND> HWNDMessageHandler::GetOwnedWindows() {
+  std::vector<HWND> owned_windows;
+
+  // Build a map associating owned HWNDs with their owners.
+  WindowOwnerMap window_owner_map;
+  ::EnumThreadWindows(GetCurrentThreadId(), &EnumOwnedWindowsProc,
+                      reinterpret_cast<LPARAM>(&window_owner_map));
+
+  // If this handler's hwnd() is not in the map it doesn't own any windows.
+  if (window_owner_map.find(hwnd()) == window_owner_map.end()) {
+    return owned_windows;
+  }
+
+  // BFS to find all transitively owned windows.
+  base::queue<HWND> to_process;
+  to_process.push(hwnd());
+
+  while (!to_process.empty()) {
+    HWND current_owner = to_process.front();
+    to_process.pop();
+
+    // Find all windows directly owned by the current HWND.
+    auto it = window_owner_map.find(current_owner);
+    if (it != window_owner_map.end()) {
+      for (HWND owned_child : it->second) {
+        // The window could have been destroyed between EnumWindows and now.
+        if (IsWindow(owned_child)) {
+          owned_windows.push_back(owned_child);
+          // Queue the current child for BFS exploration.
+          to_process.push(owned_child);
+        }
+      }
+    }
+  }
+  return owned_windows;
+}
+
 void HWNDMessageHandler::SetDwmFrameExtension(DwmFrameState state) {
   if (!delegate_->HasFrame() && !is_translucent_) {
     MARGINS m = {0, 0, 0, 0};
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index 9ad87eb..fc583188 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -133,6 +133,9 @@
   // owner of the HWND.
   virtual void SetParentOrOwner(HWND new_parent);
 
+  // Gets all descendant owned HWNDs of this handler's HWND.
+  std::vector<HWND> GetOwnedWindows();
+
   // Shows the window. If |show_state| is maximized, |pixel_restore_bounds| is
   // the bounds to restore the window to when going back to normal.
   virtual void Show(ui::mojom::WindowShowState show_state,
diff --git a/ui/views/win/hwnd_message_handler_interactive_uitest.cc b/ui/views/win/hwnd_message_handler_interactive_uitest.cc
new file mode 100644
index 0000000..c42e40e0
--- /dev/null
+++ b/ui/views/win/hwnd_message_handler_interactive_uitest.cc
@@ -0,0 +1,205 @@
+// 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 <algorithm>
+#include <memory>
+
+#include "base/containers/contains.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/mock_input_method.h"
+#include "ui/views/test/widget_test.h"
+#include "ui/views/win/hwnd_message_handler.h"
+#include "ui/views/win/hwnd_message_handler_delegate.h"
+
+namespace views {
+
+namespace {
+
+class TestHWNDMessageHandlerDelegate : public HWNDMessageHandlerDelegate {
+ public:
+  TestHWNDMessageHandlerDelegate() {
+    mock_input_method_ = std::make_unique<ui::MockInputMethod>(nullptr);
+  }
+  TestHWNDMessageHandlerDelegate(const TestHWNDMessageHandlerDelegate&) =
+      delete;
+  TestHWNDMessageHandlerDelegate& operator=(
+      const TestHWNDMessageHandlerDelegate&) = delete;
+  ~TestHWNDMessageHandlerDelegate() override = default;
+
+  // HWNDMessageHandlerDelegate:
+  ui::InputMethod* GetHWNDMessageDelegateInputMethod() override {
+    return mock_input_method_.get();
+  }
+  bool HasNonClientView() const override { return false; }
+  FrameMode GetFrameMode() const override { return FrameMode::SYSTEM_DRAWN; }
+  bool HasFrame() const override { return false; }
+  bool ShouldPaintAsActive() const override { return false; }
+  void SchedulePaint() override {}
+  bool CanResize() const override { return false; }
+  bool CanMaximize() const override { return false; }
+  bool CanMinimize() const override { return false; }
+  bool CanActivate() const override { return false; }
+  bool WidgetSizeIsClientSize() const override { return false; }
+  bool IsModal() const override { return false; }
+  int GetInitialShowState() const override { return SW_SHOWNORMAL; }
+  int GetNonClientComponent(const gfx::Point& point) const override {
+    return HTNOWHERE;
+  }
+  void GetWindowMask(const gfx::Size& size_px, SkPath* mask) override {}
+  bool GetClientAreaInsets(gfx::Insets* insets,
+                           int frame_thickness) const override {
+    return false;
+  }
+  bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override {
+    return false;
+  }
+  void GetMinMaxSize(gfx::Size* min_size, gfx::Size* max_size) const override {}
+  gfx::Size GetRootViewSize() const override { return gfx::Size(); }
+  gfx::Size DIPToScreenSize(const gfx::Size& dip_size) const override {
+    return dip_size;
+  }
+  void ResetWindowControls() override {}
+  gfx::NativeViewAccessible GetNativeViewAccessible() override {
+    return nullptr;
+  }
+  void HandleActivationChanged(bool active) override {}
+  bool HandleAppCommand(int command) override { return false; }
+  void HandleCancelMode() override {}
+  void HandleCaptureLost() override {}
+  void HandleClose() override {}
+  bool HandleCommand(int command) override { return false; }
+  void HandleAccelerator(const ui::Accelerator& accelerator) override {}
+  void HandleCreate() override {}
+  void HandleDestroying() override {}
+  void HandleDestroyed() override {}
+  bool HandleInitialFocus(ui::mojom::WindowShowState show_state) override {
+    return false;
+  }
+  void HandleDisplayChange() override {}
+  void HandleBeginWMSizeMove() override {}
+  void HandleEndWMSizeMove() override {}
+  void HandleBeginUserResize() override {}
+  void HandleEndUserResize() override {}
+  void HandleMove() override {}
+  void HandleWorkAreaChanged() override {}
+  void HandleVisibilityChanged(bool visible) override {}
+  void HandleWindowMinimizedOrRestored(bool restored) override {}
+  void HandleClientSizeChanged(const gfx::Size& new_size) override {}
+  void HandleFrameChanged() override {}
+  void HandleNativeFocus(HWND last_focused_window) override {}
+  void HandleNativeBlur(HWND focused_window) override {}
+  bool HandleMouseEvent(ui::MouseEvent* event) override { return false; }
+  void HandleKeyEvent(ui::KeyEvent* event) override {}
+  void HandleTouchEvent(ui::TouchEvent* event) override {}
+  bool HandleIMEMessage(UINT message,
+                        WPARAM w_param,
+                        LPARAM l_param,
+                        LRESULT* result) override {
+    return false;
+  }
+  void HandleInputLanguageChange(DWORD character_set,
+                                 HKL input_language_id) override {}
+  void HandlePaintAccelerated(const gfx::Rect& invalid_rect) override {}
+  void HandleMenuLoop(bool in_menu_loop) override {}
+  bool PreHandleMSG(UINT message,
+                    WPARAM w_param,
+                    LPARAM l_param,
+                    LRESULT* result) override {
+    return false;
+  }
+  void PostHandleMSG(UINT message, WPARAM w_param, LPARAM l_param) override {}
+  bool HandleScrollEvent(ui::ScrollEvent* event) override { return false; }
+  bool HandleGestureEvent(ui::GestureEvent* event) override { return false; }
+  void HandleWindowSizeChanging() override {}
+  void HandleWindowSizeUnchanged() override {}
+  void HandleWindowScaleFactorChanged(float window_scale_factor) override {}
+  void HandleHeadlessWindowBoundsChanged(const gfx::Rect& bounds) override {}
+  HBRUSH GetBackgroundPaintBrush() override { return nullptr; }
+
+ private:
+  std::unique_ptr<ui::MockInputMethod> mock_input_method_;
+};
+
+}  // namespace
+
+using HWNDMessageHandlerTest = test::DesktopWidgetTestInteractive;
+
+TEST_F(HWNDMessageHandlerTest, Init) {
+  TestHWNDMessageHandlerDelegate delegate;
+  std::unique_ptr<HWNDMessageHandler> handler(
+      HWNDMessageHandler::Create(&delegate, "test"));
+  ASSERT_TRUE(handler);
+  handler->Init(nullptr, gfx::Rect(0, 0, 100, 100));
+  ASSERT_TRUE(handler->hwnd());
+}
+
+TEST_F(HWNDMessageHandlerTest, GetOwnedWindows) {
+  TestHWNDMessageHandlerDelegate parent_delegate;
+  std::unique_ptr<HWNDMessageHandler> parent_handler(
+      HWNDMessageHandler::Create(&parent_delegate, "parent"));
+  ASSERT_TRUE(parent_handler);
+  parent_handler->Init(nullptr, gfx::Rect(0, 0, 200, 200));
+  ASSERT_TRUE(parent_handler->hwnd());
+
+  TestHWNDMessageHandlerDelegate child_delegate;
+  std::unique_ptr<HWNDMessageHandler> child_handler(
+      HWNDMessageHandler::Create(&child_delegate, "child"));
+  ASSERT_TRUE(child_handler);
+  child_handler->set_window_style(WS_POPUP);
+  child_handler->Init(parent_handler->hwnd(), gfx::Rect(0, 0, 100, 100));
+  ASSERT_TRUE(child_handler->hwnd());
+
+  std::vector<HWND> owned_windows = parent_handler->GetOwnedWindows();
+  ASSERT_EQ(1u, owned_windows.size());
+  EXPECT_TRUE(base::Contains(owned_windows, child_handler->hwnd()));
+
+  child_handler->CloseNow();
+  parent_handler->CloseNow();
+}
+
+TEST_F(HWNDMessageHandlerTest, GetOwnedWindows_Depth3) {
+  TestHWNDMessageHandlerDelegate grandparent_delegate;
+  std::unique_ptr<HWNDMessageHandler> grandparent_handler(
+      HWNDMessageHandler::Create(&grandparent_delegate, "grandparent"));
+  ASSERT_TRUE(grandparent_handler);
+  grandparent_handler->Init(nullptr, gfx::Rect(0, 0, 300, 300));
+  ASSERT_TRUE(grandparent_handler->hwnd());
+
+  TestHWNDMessageHandlerDelegate parent1_delegate;
+  std::unique_ptr<HWNDMessageHandler> parent1_handler(
+      HWNDMessageHandler::Create(&parent1_delegate, "parent1"));
+  ASSERT_TRUE(parent1_handler);
+  parent1_handler->set_window_style(WS_POPUP);
+  parent1_handler->Init(grandparent_handler->hwnd(), gfx::Rect(0, 0, 200, 200));
+  ASSERT_TRUE(parent1_handler->hwnd());
+
+  TestHWNDMessageHandlerDelegate parent2_delegate;
+  std::unique_ptr<HWNDMessageHandler> parent2_handler(
+      HWNDMessageHandler::Create(&parent2_delegate, "parent2"));
+  ASSERT_TRUE(parent2_handler);
+  parent2_handler->set_window_style(WS_POPUP);
+  parent2_handler->Init(grandparent_handler->hwnd(), gfx::Rect(0, 0, 50, 50));
+  ASSERT_TRUE(parent2_handler->hwnd());
+
+  TestHWNDMessageHandlerDelegate child_delegate;
+  std::unique_ptr<HWNDMessageHandler> child_handler(
+      HWNDMessageHandler::Create(&child_delegate, "child"));
+  ASSERT_TRUE(child_handler);
+  child_handler->set_window_style(WS_POPUP);
+  child_handler->Init(parent1_handler->hwnd(), gfx::Rect(0, 0, 100, 100));
+  ASSERT_TRUE(child_handler->hwnd());
+
+  std::vector<HWND> owned_windows = grandparent_handler->GetOwnedWindows();
+  ASSERT_EQ(3u, owned_windows.size());
+  EXPECT_TRUE(base::Contains(owned_windows, parent1_handler->hwnd()));
+  EXPECT_TRUE(base::Contains(owned_windows, parent2_handler->hwnd()));
+  EXPECT_TRUE(base::Contains(owned_windows, child_handler->hwnd()));
+
+  child_handler->CloseNow();
+  parent2_handler->CloseNow();
+  parent1_handler->CloseNow();
+  grandparent_handler->CloseNow();
+}
+
+}  // namespace views
diff --git a/ui/webui/resources/cr_components/searchbox/searchbox.html b/ui/webui/resources/cr_components/searchbox/searchbox.html
index 3e7e7594..3b417d3 100644
--- a/ui/webui/resources/cr_components/searchbox/searchbox.html
+++ b/ui/webui/resources/cr_components/searchbox/searchbox.html
@@ -164,9 +164,6 @@
     background-color: var(--color-bubble-searchbox-results-input-background, --color-searchbox-results-background);
   }
 
-  /* TODO(b/328294049): Switch all hard-coded colors to CSS color tokens. */
-  /* When input is focused and dropdown is not visible, switch searchbox background
-   * to steady state color because side panel doesn't have box shadow. */
   :host([is-lens-searchbox_]:not([dropdown-is-visible])) input:focus {
     background-color: var(--color-searchbox-background);
   }
diff --git a/url/origin.cc b/url/origin.cc
index de581dd..3224219f 100644
--- a/url/origin.cc
+++ b/url/origin.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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "url/origin.h"
 
 #include <stdint.h>
@@ -22,6 +17,7 @@
 #include "base/base64.h"
 #include "base/check.h"
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/containers/contains.h"
 #include "base/containers/span.h"
 #include "base/debug/crash_logging.h"
@@ -339,8 +335,8 @@
     pickle.WriteUInt64(0);
   }
 
-  base::span<const uint8_t> data(static_cast<const uint8_t*>(pickle.data()),
-                                 pickle.size());
+  base::span<const uint8_t> UNSAFE_TODO(
+      data(static_cast<const uint8_t*>(pickle.data()), pickle.size()));
   // Base64 encode the data to make it nicer to play with.
   return base::Base64Encode(data);
 }
diff --git a/url/url_canon_etc.cc b/url/url_canon_etc.cc
index 1b1f561..953d86a 100644
--- a/url/url_canon_etc.cc
+++ b/url/url_canon_etc.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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <array>
 #include <string_view>
 
@@ -46,13 +41,14 @@
     // write, even if we need to run it three times. (If this turns out to still
     // be a bottleneck, we could write our own vector code, but given that
     // memchr is so fast, it's unlikely to be relevant.)
-    found_whitespace = memchr(input, '\n', input_len) != nullptr ||
-                       memchr(input, '\r', input_len) != nullptr ||
-                       memchr(input, '\t', input_len) != nullptr;
+    found_whitespace = UNSAFE_TODO(memchr(input, '\n', input_len)) != nullptr ||
+                       UNSAFE_TODO(memchr(input, '\r', input_len)) != nullptr ||
+                       UNSAFE_TODO(memchr(input, '\t', input_len)) != nullptr;
   } else {
     for (int i = 0; i < input_len; i++) {
-      if (!IsRemovableURLWhitespace(input[i]))
+      if (!IsRemovableURLWhitespace(UNSAFE_TODO(input[i]))) {
         continue;
+      }
       found_whitespace = true;
       break;
     }
@@ -70,18 +66,20 @@
   // TODO(mkwst): Ideally, this would use something like `base::StartsWith`, but
   // that turns out to be difficult to do correctly given this function's
   // character type templating.
-  if (input_len > 5 && input[0] == 'd' && input[1] == 'a' && input[2] == 't' &&
-      input[3] == 'a' && input[4] == ':') {
+  if (input_len > 5 && input[0] == 'd' && UNSAFE_TODO(input[1]) == 'a' &&
+      UNSAFE_TODO(input[2]) == 't' && UNSAFE_TODO(input[3]) == 'a' &&
+      UNSAFE_TODO(input[4]) == ':') {
     *output_len = input_len;
     return input;
   }
 
   // Remove the whitespace into the new buffer and return it.
   for (int i = 0; i < input_len; i++) {
-    if (!IsRemovableURLWhitespace(input[i])) {
-      if (potentially_dangling_markup && input[i] == 0x3C)
+    if (!IsRemovableURLWhitespace(UNSAFE_TODO(input[i]))) {
+      if (potentially_dangling_markup && UNSAFE_TODO(input[i]) == 0x3C) {
         *potentially_dangling_markup = true;
-      buffer->push_back(input[i]);
+      }
+      buffer->push_back(UNSAFE_TODO(input[i]));
     }
   }
   *output_len = buffer->length();
diff --git a/url/url_canon_host.cc b/url/url_canon_host.cc
index 8e6f3016..798ce91d 100644
--- a/url/url_canon_host.cc
+++ b/url/url_canon_host.cc
@@ -4,12 +4,9 @@
 
 #include <string>
 #include <string_view>
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
 
 #include "base/check.h"
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 #include "url/url_features.h"
@@ -183,7 +180,7 @@
 // clang-format on
 
 bool IsForbiddenHostCodePoint(uint8_t ch) {
-  return ch <= 0x7F && (kHostCharacterTable[ch] & kForbiddenHost);
+  return ch <= 0x7F && (UNSAFE_TODO(kHostCharacterTable[ch]) & kForbiddenHost);
 }
 
 // RFC1034 maximum FQDN length.
@@ -213,10 +210,11 @@
   *has_non_ascii = false;
   *has_escaped = false;
   for (int i = host.begin; i < end; i++) {
-    if (static_cast<UCHAR>(spec[i]) >= 0x80)
+    if (static_cast<UCHAR>(UNSAFE_TODO(spec[i])) >= 0x80) {
       *has_non_ascii = true;
-    else if (spec[i] == '%')
+    } else if (UNSAFE_TODO(spec[i]) == '%') {
       *has_escaped = true;
+    }
   }
 }
 
@@ -266,7 +264,7 @@
 
     if (source < 0x80) {
       // We have ASCII input, we can use our lookup table.
-      unsigned char replacement = kHostCharLookup[source];
+      unsigned char replacement = UNSAFE_TODO(kHostCharLookup[source]);
       if (!replacement) {
         // Invalid character, add it as percent-escaped and mark as failed.
         AppendEscapedChar(source, output);
@@ -463,7 +461,7 @@
 
   if (has_non_ascii || has_escaped) {
     return DoComplexHost<canon_mode>(
-        std::basic_string_view<CHAR>(&spec[host.begin],
+        std::basic_string_view<CHAR>(&UNSAFE_TODO(spec[host.begin]),
                                      static_cast<size_t>(host.len)),
         has_non_ascii, has_escaped, output);
   }
diff --git a/url/url_canon_icu.cc b/url/url_canon_icu.cc
index 086d7bb..f3fe39c3 100644
--- a/url/url_canon_icu.cc
+++ b/url/url_canon_icu.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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 // ICU-based character set converter.
 
 #include "url/url_canon_icu.h"
@@ -16,6 +11,7 @@
 #include <string.h>
 
 #include "base/check.h"
+#include "base/compiler_specific.h"
 #include "base/memory/stack_allocated.h"
 #include "base/numerics/safe_conversions.h"
 #include "third_party/icu/source/common/unicode/ucnv.h"
@@ -102,7 +98,7 @@
 
   do {
     UErrorCode err = U_ZERO_ERROR;
-    char* dest = &output->data()[begin_offset];
+    char* dest = &UNSAFE_TODO(output->data()[begin_offset]);
     int required_capacity =
         ucnv_fromUChars(converter_, dest, dest_capacity, input.data(),
                         base::checked_cast<int32_t>(input.size()), &err);
diff --git a/url/url_canon_icu_unittest.cc b/url/url_canon_icu_unittest.cc
index 0730a1a3..712f5d4f 100644
--- a/url/url_canon_icu_unittest.cc
+++ b/url/url_canon_icu_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 "url/url_canon_icu.h"
 
 #include <stddef.h>
diff --git a/url/url_canon_ip.cc b/url/url_canon_ip.cc
index d9a4c45e..4cc15ec 100644
--- a/url/url_canon_ip.cc
+++ b/url/url_canon_ip.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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "url/url_canon_ip.h"
 
 #include <stdint.h>
@@ -15,6 +10,7 @@
 #include <limits>
 
 #include "base/check.h"
+#include "base/compiler_specific.h"
 #include "url/url_canon_internal.h"
 #include "url/url_features.h"
 
@@ -61,7 +57,8 @@
 
   for (int i = 0; i < 16; i += 2) {
     // Test for 16 bits worth of zero.
-    bool is_zero = (address[i] == 0 && address[i + 1] == 0);
+    bool is_zero =
+        (UNSAFE_TODO(address[i]) == 0 && UNSAFE_TODO(address[i + 1]) == 0);
 
     if (is_zero) {
       // Add the zero to the current range (or start a new one).
@@ -94,7 +91,7 @@
     // If it's not an IPv6 address, scan for characters that should *only*
     // exist in an IPv6 address.
     for (int i = host.begin; i < host.end(); i++) {
-      switch (spec[i]) {
+      switch (UNSAFE_TODO(spec[i])) {
         case '[':
         case ']':
         case ':':
@@ -123,10 +120,11 @@
 void AppendIPv4Address(const unsigned char address[4], CanonOutput* output) {
   for (int i = 0; i < 4; i++) {
     char str[16];
-    _itoa_s(address[i], str, 10);
+    _itoa_s(UNSAFE_TODO(address[i]), str, 10);
 
-    for (int ch = 0; str[ch] != 0; ch++)
-      output->push_back(str[ch]);
+    for (int ch = 0; UNSAFE_TODO(str[ch]) != 0; ch++) {
+      output->push_back(UNSAFE_TODO(str[ch]));
+    }
 
     if (i != 3)
       output->push_back('.');
@@ -152,15 +150,16 @@
       i = contraction_range.end();
     } else {
       // Consume the next 16 bits from |address|.
-      int x = address[i] << 8 | address[i + 1];
+      int x = UNSAFE_TODO(address[i]) << 8 | UNSAFE_TODO(address[i + 1]);
 
       i += 2;
 
       // Stringify the 16 bit number (at most requires 4 hex digits).
       char str[5];
       _itoa_s(x, str, 16);
-      for (int ch = 0; str[ch] != 0; ++ch)
-        output->push_back(str[ch]);
+      for (int ch = 0; UNSAFE_TODO(str[ch]) != 0; ++ch) {
+        output->push_back(UNSAFE_TODO(str[ch]));
+      }
 
       // Put a colon after each number, except the last.
       if (i < 16)
diff --git a/url/url_canon_mailtourl.cc b/url/url_canon_mailtourl.cc
index 1e8d2db..0c7a955 100644
--- a/url/url_canon_mailtourl.cc
+++ b/url/url_canon_mailtourl.cc
@@ -2,13 +2,9 @@
 // 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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 // Functions for canonicalizing "mailto:" URLs.
 
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 #include "url/url_file.h"
@@ -64,7 +60,7 @@
     // ASCII characters alone.
     size_t end = static_cast<size_t>(parsed.path.end());
     for (size_t i = static_cast<size_t>(parsed.path.begin); i < end; ++i) {
-      UCHAR uch = static_cast<UCHAR>(source.path[i]);
+      UCHAR uch = static_cast<UCHAR>(UNSAFE_TODO(source.path[i]));
       if (ShouldEncodeMailboxCharacter<UCHAR>(uch))
         success &= AppendUTF8EscapedChar(source.path, &i, end, output);
       else
diff --git a/url/url_canon_path.cc b/url/url_canon_path.cc
index 7e9314a..e0140a2 100644
--- a/url/url_canon_path.cc
+++ b/url/url_canon_path.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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 #include <limits.h>
 
 #include <optional>
@@ -14,6 +9,7 @@
 
 #include "base/check.h"
 #include "base/check_op.h"
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 #include "url/url_features.h"
@@ -115,7 +111,7 @@
     *consumed_len = 0;
     return DIRECTORY_CUR;
   }
-  if (IsSlashOrBackslash(spec[after_dot])) {
+  if (IsSlashOrBackslash(UNSAFE_TODO(spec[after_dot]))) {
     // Single dot followed by a slash.
     *consumed_len = 1;  // Consume the slash
     return DIRECTORY_CUR;
@@ -129,7 +125,7 @@
       *consumed_len = second_dot_len;
       return DIRECTORY_UP;
     }
-    if (IsSlashOrBackslash(spec[after_second_dot])) {
+    if (IsSlashOrBackslash(UNSAFE_TODO(spec[after_second_dot]))) {
       // Double dot followed by a slash.
       *consumed_len = second_dot_len + 1;
       return DIRECTORY_UP;
@@ -208,7 +204,7 @@
     } else {
       // Normal ASCII character or 8-bit input, use the lookup table.
       unsigned char out_ch = static_cast<unsigned char>(uch);
-      unsigned char flags = kPathCharLookup[out_ch];
+      unsigned char flags = UNSAFE_TODO(kPathCharLookup[out_ch]);
       if (flags & SPECIAL) {
         // Needs special handling of some sort.
         size_t dotlen;
diff --git a/url/url_canon_pathurl.cc b/url/url_canon_pathurl.cc
index 5697296..a84b259 100644
--- a/url/url_canon_pathurl.cc
+++ b/url/url_canon_pathurl.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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 // Functions for canonicalizing "path" URLs. Not to be confused with the path
 // of a URL, these are URLs that have no authority section, only a path. For
 // example, "javascript:" and "data:".
diff --git a/url/url_canon_query.cc b/url/url_canon_query.cc
index 693736f..702d2e5 100644
--- a/url/url_canon_query.cc
+++ b/url/url_canon_query.cc
@@ -3,11 +3,8 @@
 // found in the LICENSE file.
 
 #include <string_view>
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
 
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 
@@ -53,10 +50,12 @@
 void AppendRaw8BitQueryString(const CHAR* source, int length,
                               CanonOutput* output) {
   for (int i = 0; i < length; i++) {
-    if (!IsQueryChar(static_cast<unsigned char>(source[i])))
-      AppendEscapedChar(static_cast<unsigned char>(source[i]), output);
-    else  // Doesn't need escaping.
-      output->push_back(static_cast<char>(source[i]));
+    if (!IsQueryChar(static_cast<unsigned char>(UNSAFE_TODO(source[i])))) {
+      AppendEscapedChar(static_cast<unsigned char>(UNSAFE_TODO(source[i])),
+                        output);
+    } else {  // Doesn't need escaping.
+      output->push_back(static_cast<char>(UNSAFE_TODO(source[i])));
+    }
   }
 }
 
diff --git a/url/url_canon_stdurl.cc b/url/url_canon_stdurl.cc
index f02e9ec2..a98d5a6 100644
--- a/url/url_canon_stdurl.cc
+++ b/url/url_canon_stdurl.cc
@@ -2,14 +2,10 @@
 // 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/350788890): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 // Functions to canonicalize "standard" URLs, which are ones that have an
 // authority section including a host name.
 
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 #include "url/url_constants.h"
@@ -73,7 +69,8 @@
     // Port: the port canonicalizer will handle the colon.
     if (scheme_supports_ports) {
       int default_port = DefaultPortForScheme(std::string_view(
-          &output->data()[new_parsed->scheme.begin], new_parsed->scheme.len));
+          &UNSAFE_TODO(output->data()[new_parsed->scheme.begin]),
+          new_parsed->scheme.len));
       success &= CanonicalizePort(source.port, parsed.port, default_port,
                                   output, &new_parsed->port);
     } else {
diff --git a/v8 b/v8
index f409d26..8737ccb 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit f409d26cf3aebc05e1312f2181be715eea11db91
+Subproject commit 8737ccb0fe3bd51b2bfc64ea7328215ece777840